From f329cf6e2a1614306b5846c9b1791e2549af7a69 Mon Sep 17 00:00:00 2001 From: Chris T Date: Wed, 30 Mar 2022 12:22:20 -0400 Subject: [PATCH 1/8] shared ontology subscribe: subscribe and unsubscribe from ontology --- .../api/v1/controller/OntologyController.java | 44 +++++ .../breedinginsight/daos/ObservationDAO.java | 20 +++ .../daos/ProgramOntologyDAO.java | 20 ++- .../org/breedinginsight/daos/TraitDAO.java | 20 ++- .../services/OntologyService.java | 60 ++++++- .../services/TraitService.java | 16 +- .../java/org/breedinginsight/TestUtils.java | 14 ++ .../OntologyControllerIntegrationTest.java | 162 ++++++++++++++---- ...BrAPIOntologyControllerIntegrationTest.sql | 19 +- 9 files changed, 327 insertions(+), 48 deletions(-) diff --git a/src/main/java/org/breedinginsight/api/v1/controller/OntologyController.java b/src/main/java/org/breedinginsight/api/v1/controller/OntologyController.java index cd02ef6ea..edaa00552 100644 --- a/src/main/java/org/breedinginsight/api/v1/controller/OntologyController.java +++ b/src/main/java/org/breedinginsight/api/v1/controller/OntologyController.java @@ -135,4 +135,48 @@ public HttpResponse>> revokeOntology( return HttpResponse.status(HttpStatus.NOT_FOUND, e.getMessage()); } } + + /** + * Scoped under the program that is subscribing. Accept a shared ontology. + * + * @param programId -- Program that is subscribing to an ontology + * @param sharingProgramId -- Program that has shared its ontology. + * @return + */ + @Put("/programs/{programId}/ontology/subscribe/{sharingProgramId}") + @Produces(MediaType.APPLICATION_JSON) + @ProgramSecured(roleGroups = {ProgramSecuredRoleGroup.ALL}) + public HttpResponse>> subscribeOntology( + @PathVariable UUID programId, @PathVariable UUID sharingProgramId) { + try { + ontologyService.subscribeOntology(programId, sharingProgramId); + return HttpResponse.ok(); + } catch (UnprocessableEntityException e) { + return HttpResponse.status(HttpStatus.UNPROCESSABLE_ENTITY, e.getMessage()); + } catch (DoesNotExistException e) { + return HttpResponse.status(HttpStatus.NOT_FOUND, e.getMessage()); + } + } + + /** + * Scoped under the program that is subscribing. Unsubscribe from a shared ontology. + * + * @param programId -- Program that is unsubscribing from an ontology + * @param sharingProgramId -- Program that has shared its ontology. + * @return + */ + @Put("/programs/{programId}/ontology/unsubscribe/{sharingProgramId}") + @Produces(MediaType.APPLICATION_JSON) + @ProgramSecured(roleGroups = {ProgramSecuredRoleGroup.ALL}) + public HttpResponse>> unsubscribeOntology( + @PathVariable UUID programId, @PathVariable UUID sharingProgramId) { + try { + ontologyService.unsubscribeOntology(programId, sharingProgramId); + return HttpResponse.ok(); + } catch (UnprocessableEntityException e) { + return HttpResponse.status(HttpStatus.UNPROCESSABLE_ENTITY, e.getMessage()); + } catch (DoesNotExistException e) { + return HttpResponse.status(HttpStatus.NOT_FOUND, e.getMessage()); + } + } } diff --git a/src/main/java/org/breedinginsight/daos/ObservationDAO.java b/src/main/java/org/breedinginsight/daos/ObservationDAO.java index b6f7190ae..2dbaab866 100644 --- a/src/main/java/org/breedinginsight/daos/ObservationDAO.java +++ b/src/main/java/org/breedinginsight/daos/ObservationDAO.java @@ -33,6 +33,7 @@ import javax.inject.Inject; import java.util.List; import java.util.Optional; +import java.util.UUID; import static org.brapi.v2.model.BrAPIWSMIMEDataTypes.APPLICATION_JSON; @@ -77,6 +78,25 @@ public List getObservationsByVariableDbIds(List observ } + public List getObservationsByVariableAndBrAPIProgram(String brapiProgramId, List observationVariableDbIds) { + + try { + BrAPIObservationSearchRequest request = new BrAPIObservationSearchRequest() + .observationVariableDbIds(observationVariableDbIds) + .programDbIds(List.of(brapiProgramId)); + + ObservationsApi api = brAPIProvider.getObservationsAPI(BrAPIClientType.PHENO); + return BrAPIDAOUtil.search( + api::searchObservationsPost, + this::searchObservationsSearchResultsDbIdGet, + request + ); + } catch (ApiException e) { + throw new InternalServerException("Observations brapi search error", e); + } + + } + private ApiResponse, Optional>> searchObservationsSearchResultsDbIdGet(String searchResultsDbId, Integer page, Integer pageSize) throws ApiException { ObservationsApi api = brAPIProvider.getObservationsAPI(BrAPIClientType.PHENO); diff --git a/src/main/java/org/breedinginsight/daos/ProgramOntologyDAO.java b/src/main/java/org/breedinginsight/daos/ProgramOntologyDAO.java index 2068f34cf..b72af5c84 100644 --- a/src/main/java/org/breedinginsight/daos/ProgramOntologyDAO.java +++ b/src/main/java/org/breedinginsight/daos/ProgramOntologyDAO.java @@ -20,11 +20,14 @@ import org.breedinginsight.dao.db.tables.daos.ProgramOntologyDao; import org.breedinginsight.dao.db.tables.daos.ProgramSharedOntologyDao; import org.breedinginsight.dao.db.tables.pojos.ProgramSharedOntologyEntity; +import org.breedinginsight.model.ProgramOntology; import org.jooq.Configuration; import org.jooq.DSLContext; import javax.inject.Inject; import javax.inject.Singleton; +import javax.swing.text.html.Option; +import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.UUID; @@ -62,11 +65,18 @@ public void revokeSharedOntology(ProgramSharedOntologyEntity sharedOntology) { programSharedOntologyDao.delete(sharedOntology); } - public boolean programSubscribedSharedOntology(UUID programId) { + public Optional getSubscribedSharedOntology(UUID programId) { List shareRecords = programSharedOntologyDao.fetchBySharedProgramId(programId); - return !shareRecords.stream() - .filter(shareRecord -> shareRecord.getActive()) - .collect(Collectors.toList()) - .isEmpty(); + return shareRecords.size() > 0 ? Optional.of(shareRecords.get(0)) : Optional.empty(); + } + + public void acceptSharedOntology(ProgramSharedOntologyEntity sharedOntology) { + sharedOntology.setActive(true); + programSharedOntologyDao.update(sharedOntology); + } + + public void denySharedOntology(ProgramSharedOntologyEntity sharedOntology) { + sharedOntology.setActive(false); + programSharedOntologyDao.update(sharedOntology); } } diff --git a/src/main/java/org/breedinginsight/daos/TraitDAO.java b/src/main/java/org/breedinginsight/daos/TraitDAO.java index fd73a4f88..f04afa546 100644 --- a/src/main/java/org/breedinginsight/daos/TraitDAO.java +++ b/src/main/java/org/breedinginsight/daos/TraitDAO.java @@ -218,6 +218,25 @@ public List getObservationsForTraits(List traitIds) { return observationDao.getObservationsByVariableDbIds(brapiVariableIds); } + public List getObservationsForTraitsByBrAPIProgram(String brapiProgramId, List traitIds) { + + List ids = traitIds.stream() + .map(trait -> trait.toString()) + .collect(Collectors.toList()); + + List variables = searchVariables(ids); + + // TODO: make sure have all expected external references + if (variables.size() != ids.size()) { + throw new InternalServerException("Observation variables search results mismatch"); + } + + List brapiVariableIds = variables.stream() + .map(variable -> variable.getObservationVariableDbId()).collect(Collectors.toList()); + + return observationDao.getObservationsByVariableAndBrAPIProgram(brapiProgramId, brapiVariableIds); + } + public List searchVariables(List variableIds) { try { BrAPIObservationVariableSearchRequest request = new BrAPIObservationVariableSearchRequest() @@ -573,5 +592,4 @@ private void saturateTrait(Trait trait, BrAPIObservationVariable brApiVariable) Scale scale = trait.getScale(); scale.setBrAPIProperties(brApiVariable.getScale()); } - } diff --git a/src/main/java/org/breedinginsight/services/OntologyService.java b/src/main/java/org/breedinginsight/services/OntologyService.java index 8a515e0cb..75317435a 100644 --- a/src/main/java/org/breedinginsight/services/OntologyService.java +++ b/src/main/java/org/breedinginsight/services/OntologyService.java @@ -2,6 +2,8 @@ import io.micronaut.http.HttpStatus; import io.micronaut.http.exceptions.HttpStatusException; +import io.micronaut.http.server.exceptions.InternalServerException; +import org.brapi.v2.model.core.BrAPIProgram; import org.breedinginsight.api.auth.AuthenticatedUser; import org.breedinginsight.api.model.v1.request.SharedOntologyProgramRequest; import org.breedinginsight.api.model.v1.response.ValidationError; @@ -12,6 +14,7 @@ import org.breedinginsight.daos.TraitDAO; import org.breedinginsight.model.Program; import org.breedinginsight.model.SharedProgram; +import org.breedinginsight.model.Trait; import org.breedinginsight.services.exceptions.DoesNotExistException; import org.breedinginsight.services.exceptions.UnprocessableEntityException; import org.breedinginsight.services.exceptions.ValidatorException; @@ -125,18 +128,21 @@ private SharedProgram formatResponse(Program program) { } private Boolean ontologyIsEditable(ProgramSharedOntologyEntity sharedOntologyEntity) { - if (sharedOntologyEntity.getActive()) { - /* TODO: Add in when checking for edits // Get all trait ids for the program - List traitIds = traitService.getByProgramId(sharedOntologyEntity.getSharedProgramId(), true).stream() + List traitIds = traitService.getSubscribedOntologyTraits(sharedOntologyEntity.getSharedProgramId()).stream() .map(trait -> trait.getId()) .collect(Collectors.toList()); + // Get the brapi program id + List program = programDAO.get(sharedOntologyEntity.getSharedProgramId()); + if (program.size() == 0) { + throw new InternalServerException("Missing program should have been caught by now"); + } + BrAPIProgram brAPIProgram = programDAO.getProgramBrAPI(program.get(0)); + // Get all observations for the ontology - return traitDAO.getObservationsForTraits(traitIds).isEmpty(); - */ - return true; + return traitDAO.getObservationsForTraitsByBrAPIProgram(brAPIProgram.getProgramDbId(), traitIds).isEmpty(); } else { return true; } @@ -164,7 +170,7 @@ public List shareOntology(@NotNull UUID programId, AuthenticatedU } // Don't allow shared if program is already subscribe to shared ontology - if (programOntologyDAO.programSubscribedSharedOntology(programId)) { + if (programOntologyDAO.getSubscribedSharedOntology(programId).isPresent()) { throw new UnprocessableEntityException("Program is subscribed to a shared ontology and cannot share its own."); } @@ -234,4 +240,44 @@ public void revokeOntology(@NotNull UUID programId, @NotNull UUID sharedProgramI // Remove record from db programOntologyDAO.revokeSharedOntology(sharedOntology); } + + public void subscribeOntology(UUID programId, UUID sharingProgramId) throws DoesNotExistException, UnprocessableEntityException { + // Check that program exists + Program program = getProgram(programId); + + // Check that shared program exists + Optional optionalSharedOntology = programOntologyDAO.getSharedOntologyById(sharingProgramId, programId); + if (optionalSharedOntology.isEmpty()) { + throw new DoesNotExistException("Shared ontology between specified programs was not found."); + } + ProgramSharedOntologyEntity sharedOntology = optionalSharedOntology.get(); + + // Check that program does not have any traits of its own + List traits = traitDAO.getTraitsByProgramId(programId); + if (traits.size() > 0) { + throw new UnprocessableEntityException("Program already has traits, cannot subscribe to a shared ontology"); + } + + // Subscribe + programOntologyDAO.acceptSharedOntology(sharedOntology); + } + + public void unsubscribeOntology(UUID programId, UUID sharingProgramId) throws DoesNotExistException, UnprocessableEntityException { + // Check that program exists + Program program = getProgram(programId); + + // Check that shared program exists + Optional optionalSharedOntology = programOntologyDAO.getSharedOntologyById(sharingProgramId, programId); + if (optionalSharedOntology.isEmpty()) { + throw new DoesNotExistException("Shared ontology between specified programs was not found."); + } + ProgramSharedOntologyEntity sharedOntology = optionalSharedOntology.get(); + + if (!ontologyIsEditable(sharedOntology)) { + throw new UnprocessableEntityException("Shared program has recorded observations on shared traits and cannot unsubscribe."); + } + + // Subscribe + programOntologyDAO.denySharedOntology(sharedOntology); + } } diff --git a/src/main/java/org/breedinginsight/services/TraitService.java b/src/main/java/org/breedinginsight/services/TraitService.java index 7fccf4351..2a8399e45 100644 --- a/src/main/java/org/breedinginsight/services/TraitService.java +++ b/src/main/java/org/breedinginsight/services/TraitService.java @@ -28,6 +28,7 @@ import org.breedinginsight.api.model.v1.response.ValidationErrors; import org.breedinginsight.dao.db.enums.DataType; import org.breedinginsight.dao.db.tables.pojos.MethodEntity; +import org.breedinginsight.dao.db.tables.pojos.ProgramSharedOntologyEntity; import org.breedinginsight.dao.db.tables.pojos.ScaleEntity; import org.breedinginsight.dao.db.tables.pojos.TraitEntity; import org.breedinginsight.daos.*; @@ -53,6 +54,7 @@ public class TraitService { private ObservationDAO observationDAO; private ProgramService programService; private ProgramOntologyService programOntologyService; + private ProgramOntologyDAO programOntologyDAO; private ProgramObservationLevelService programObservationLevelService; private UserService userService; private TraitValidatorService traitValidator; @@ -64,7 +66,8 @@ public class TraitService { @Inject public TraitService(TraitDAO traitDao, MethodDAO methodDao, ScaleDAO scaleDao, ObservationDAO observationDao, ProgramService programService, ProgramOntologyService programOntologyService, ProgramObservationLevelService programObservationLevelService, - UserService userService, TraitValidatorService traitValidator, DSLContext dsl, TraitValidatorError traitValidatorError) { + UserService userService, TraitValidatorService traitValidator, DSLContext dsl, TraitValidatorError traitValidatorError, + ProgramOntologyDAO programOntologyDAO) { this.traitDAO = traitDao; this.methodDAO = methodDao; this.scaleDAO = scaleDao; @@ -76,6 +79,7 @@ public TraitService(TraitDAO traitDao, MethodDAO methodDao, ScaleDAO scaleDao, O this.traitValidator = traitValidator; this.dsl = dsl; this.traitValidatorError = traitValidatorError; + this.programOntologyDAO = programOntologyDAO; } public List getByProgramId(UUID programId, boolean getFullTrait) throws DoesNotExistException { @@ -92,6 +96,16 @@ public List getByProgramId(UUID programId, boolean getFullTrait) throws D } + public List getSubscribedOntologyTraits(UUID programId) { + Optional optionalSharedOntology = programOntologyDAO.getSubscribedSharedOntology(programId); + if (optionalSharedOntology.isEmpty()) { + return new ArrayList<>(); + } + ProgramSharedOntologyEntity sharedOntology = optionalSharedOntology.get(); + + return traitDAO.getTraitsFullByProgramId(sharedOntology.getProgramId()); + } + public List getByProgramIds(List programIds, boolean getFullTrait) throws DoesNotExistException { if (programIds.stream().anyMatch(programId -> programService.exists(programId) == false)) { diff --git a/src/test/java/org/breedinginsight/TestUtils.java b/src/test/java/org/breedinginsight/TestUtils.java index ad1dc79b1..effb88082 100644 --- a/src/test/java/org/breedinginsight/TestUtils.java +++ b/src/test/java/org/breedinginsight/TestUtils.java @@ -28,6 +28,7 @@ import org.breedinginsight.api.model.v1.request.ProgramRequest; import org.breedinginsight.api.v1.controller.metadata.SortOrder; import org.breedinginsight.model.Program; +import org.breedinginsight.model.Trait; import se.sawano.java.text.AlphanumericComparator; import java.io.File; @@ -219,4 +220,17 @@ public static HttpResponse getUploadedFile(RxHttpClient client, UUID pro return response; } } + + public static void insertTestTraits(Gson gson, RxHttpClient client, Program program, List traits) { + + String url = String.format("/programs/%s/traits", program.getId()); + String json = gson.toJson(traits); + Flowable> call = client.exchange( + POST(url, json) + .contentType(MediaType.APPLICATION_JSON) + .cookie(new NettyCookie("phylo-token", "test-registered-user")), String.class + ); + + HttpResponse response = call.blockingFirst(); + } } diff --git a/src/test/java/org/breedinginsight/api/v1/controller/OntologyControllerIntegrationTest.java b/src/test/java/org/breedinginsight/api/v1/controller/OntologyControllerIntegrationTest.java index 7228822db..8e5183549 100644 --- a/src/test/java/org/breedinginsight/api/v1/controller/OntologyControllerIntegrationTest.java +++ b/src/test/java/org/breedinginsight/api/v1/controller/OntologyControllerIntegrationTest.java @@ -11,6 +11,7 @@ import io.micronaut.http.netty.cookies.NettyCookie; import io.micronaut.test.annotation.MicronautTest; import io.reactivex.Flowable; +import org.brapi.v2.model.core.BrAPIProgram; import org.brapi.v2.model.pheno.BrAPIObservation; import org.brapi.v2.model.pheno.BrAPIObservationVariable; import org.breedinginsight.BrAPITest; @@ -25,6 +26,7 @@ import org.breedinginsight.daos.SpeciesDAO; import org.breedinginsight.daos.UserDAO; import org.breedinginsight.model.*; +import org.breedinginsight.services.exceptions.UnprocessableEntityException; import org.jooq.DSLContext; import org.junit.jupiter.api.*; @@ -50,6 +52,7 @@ public class OntologyControllerIntegrationTest extends BrAPITest { private Program mainProgram; private Program otherProgram; private Program thirdProgram; + private Program fourthProgram; @Inject private DSLContext dsl; @@ -111,24 +114,35 @@ void setup() throws Exception { .species(speciesRequest) .key("OTC") .build(); + ProgramRequest programRequest4 = ProgramRequest.builder() + .name("Test Program4") + .abbreviation("test3") + .documentationUrl("localhost:8080") + .objective("To test things") + .species(speciesRequest) + .key("OTD") + .build(); + TestUtils.insertAndFetchTestProgram(gson, client, programRequest1); TestUtils.insertAndFetchTestProgram(gson, client, programRequest2); TestUtils.insertAndFetchTestProgram(gson, client, programRequest3); + TestUtils.insertAndFetchTestProgram(gson, client, programRequest4); // Get main program List programs = programDAO.getAll(); mainProgram = programs.get(0); otherProgram = programs.get(1); thirdProgram = programs.get(2); + fourthProgram = programs.get(3); dsl.execute(securityFp.get("InsertProgramRolesBreeder"), testUser.getId().toString(), mainProgram.getId().toString()); dsl.execute(securityFp.get("InsertProgramRolesBreeder"), testUser.getId().toString(), otherProgram.getId().toString()); + dsl.execute(securityFp.get("InsertProgramRolesBreeder"), testUser.getId().toString(), thirdProgram.getId().toString()); // Add trait to program - addTrait(otherProgram); - // Add a single observation to all traits - super.getBrapiDsl().execute(brapiObservationFp.get("AddObservations")); + addTrait(mainProgram); + addTrait(thirdProgram); } private void addTrait(Program program) { @@ -155,13 +169,7 @@ private void addTrait(Program program) { List traits = List.of(trait); // Call endpoint - Flowable> call = client.exchange( - POST("/programs/" + program.getId() + "/traits", traits) - .contentType(MediaType.APPLICATION_JSON) - .cookie(new NettyCookie("phylo-token", "test-registered-user")), String.class - ); - HttpResponse response = call.blockingFirst(); - assertEquals(HttpStatus.OK, response.getStatus()); + TestUtils.insertTestTraits(gson, client, program, traits); } @Test @@ -177,7 +185,7 @@ void getAllProgramsNoSharedPrograms() { JsonObject result = JsonParser.parseString(response.body()).getAsJsonObject().getAsJsonObject("result"); JsonArray data = result.getAsJsonArray("data"); - assertEquals(2, data.size(), "Wrong number of programs returned"); + assertEquals(3, data.size(), "Wrong number of programs returned"); // Check all are not shared and are inactive for (JsonElement element: data) { @@ -196,6 +204,7 @@ void addSharedPrograms() { String url = String.format("/programs/%s/ontology/shared/programs", mainProgram.getId()); List requests = new ArrayList<>(); requests.add(new SharedOntologyProgramRequest(otherProgram.getId(), otherProgram.getName())); + requests.add(new SharedOntologyProgramRequest(thirdProgram.getId(), thirdProgram.getName())); String json = gson.toJson(requests); Flowable> call = client.exchange( @@ -209,7 +218,7 @@ void addSharedPrograms() { JsonObject result = JsonParser.parseString(response.body()).getAsJsonObject().getAsJsonObject("result"); JsonArray data = result.getAsJsonArray("data"); - assertEquals(1, data.size(), "Wrong number of programs returned"); + assertEquals(2, data.size(), "Wrong number of programs returned"); // Check all are not shared and are inactive for (JsonElement element: data) { @@ -222,14 +231,40 @@ void addSharedPrograms() { } @Test - @Order(2) - void shareOntologySubscribedToOtherProgram() { - // TODO: When subscribe ontology card is done - // Cannot share ontology if you are using a shared ontology + @Order(3) + void subscribeOntologyProgramHasTraitsError() { + String url = String.format("/programs/%s/ontology/subscribe/%s", thirdProgram.getId(), mainProgram.getId()); + + Flowable> call = client.exchange( + PUT(url, "") + .contentType(MediaType.APPLICATION_JSON) + .cookie(new NettyCookie("phylo-token", "test-registered-user")), String.class + ); + + HttpClientResponseException e = Assertions.assertThrows(HttpClientResponseException.class, () -> { + HttpResponse response = call.blockingFirst(); + }); + + assertEquals(HttpStatus.UNPROCESSABLE_ENTITY, e.getStatus()); } @Test @Order(3) + void subscribeOntologySuccess() { + String url = String.format("/programs/%s/ontology/subscribe/%s", otherProgram.getId(), mainProgram.getId()); + + Flowable> call = client.exchange( + PUT(url, "") + .contentType(MediaType.APPLICATION_JSON) + .cookie(new NettyCookie("phylo-token", "test-registered-user")), String.class + ); + + HttpResponse response = call.blockingFirst(); + assertEquals(HttpStatus.OK, response.getStatus()); + } + + @Test + @Order(4) void getAllProgramsSharedPrograms() { String url = String.format("/programs/%s/ontology/shared/programs", mainProgram.getId()); Flowable> call = client.exchange( @@ -241,27 +276,28 @@ void getAllProgramsSharedPrograms() { JsonObject result = JsonParser.parseString(response.body()).getAsJsonObject().getAsJsonObject("result"); JsonArray data = result.getAsJsonArray("data"); - assertEquals(2, data.size(), "Wrong number of programs returned"); + assertEquals(3, data.size(), "Wrong number of programs returned"); // Check all are not shared and are inactive for (JsonElement element: data) { JsonObject program = element.getAsJsonObject(); - if (program.get("programId").getAsString().equals(otherProgram.getId().toString())) { + if (program.get("programId").getAsString().equals(fourthProgram.getId().toString())) { + assertFalse(program.get("shared").getAsBoolean()); + } else { assertTrue(program.get("shared").getAsBoolean(), "Shared should have been true"); - assertFalse(program.get("accepted").getAsBoolean(), "Accepted should have been false"); assertTrue(program.get("editable").getAsBoolean(), "Editable should have been false"); - } else { - assertFalse(program.get("shared").getAsBoolean(), "Shared should have been false"); - assertNull(program.get("accepted"), "Accepted should have been false"); - assertNull(program.get("editable"), "Editable should have been false"); + if (program.get("programId").getAsString().equals(otherProgram.getId().toString())) { + assertTrue(program.get("accepted").getAsBoolean()); + } else { + assertFalse(program.get("accepted").getAsBoolean()); + } } - } } @Test - @Order(3) + @Order(4) void getOnlySharedPrograms() { String url = String.format("/programs/%s/ontology/shared/programs?shared=true", mainProgram.getId()); Flowable> call = client.exchange( @@ -273,30 +309,92 @@ void getOnlySharedPrograms() { JsonObject result = JsonParser.parseString(response.body()).getAsJsonObject().getAsJsonObject("result"); JsonArray data = result.getAsJsonArray("data"); - assertEquals(1, data.size(), "Wrong number of programs returned"); + assertEquals(2, data.size(), "Wrong number of programs returned"); // Check all are not shared and are inactive for (JsonElement element: data) { JsonObject program = element.getAsJsonObject(); assertTrue(program.get("shared").getAsBoolean(), "Shared should have been true"); - assertFalse(program.get("accepted").getAsBoolean(), "Accepted should have been false"); - assertTrue(program.get("editable").getAsBoolean(), "Editable should have been false"); } } + @Test + @Order(4) + void shareOntologySubscribedToOtherProgram() { + // Cannot share ontology if you are using a shared ontology + String url = String.format("/programs/%s/ontology/shared/programs", otherProgram.getId()); + List requests = new ArrayList<>(); + requests.add(new SharedOntologyProgramRequest(fourthProgram.getId(), fourthProgram.getName())); + String json = gson.toJson(requests); + + Flowable> call = client.exchange( + POST(url, json) + .contentType(MediaType.APPLICATION_JSON) + .cookie(new NettyCookie("phylo-token", "test-registered-user")), String.class + ); + + HttpClientResponseException e = Assertions.assertThrows(HttpClientResponseException.class, () -> { + HttpResponse response = call.blockingFirst(); + }); + assertEquals(HttpStatus.UNPROCESSABLE_ENTITY, e.getStatus()); + } + @Test @Order(4) void revokeOntologyUneditable() { - // TODO: When subscribe ontology card is done // Ontology cannot be revoke if shared program has accepted and has observations + super.getBrapiDsl().execute(brapiObservationFp.get("AddObservations"), otherProgram.getId().toString()); + + String url = String.format("/programs/%s/ontology/shared/programs/%s", mainProgram.getId(), otherProgram.getId()); + Flowable> call = client.exchange( + DELETE(url).cookie(new NettyCookie("phylo-token", "test-registered-user")), String.class + ); + + HttpClientResponseException e = Assertions.assertThrows(HttpClientResponseException.class, () -> { + HttpResponse response = call.blockingFirst(); + }); + assertEquals(HttpStatus.UNPROCESSABLE_ENTITY, e.getStatus()); + + super.getBrapiDsl().execute(brapiObservationFp.get("DeleteObservations")); + } + + @Test + @Order(4) + void unsubscribeOntologyUneditableError() { + super.getBrapiDsl().execute(brapiObservationFp.get("AddObservations"), otherProgram.getId().toString()); + + String url = String.format("/programs/%s/ontology/unsubscribe/%s", otherProgram.getId(), mainProgram.getId()); + Flowable> call = client.exchange( + PUT(url, "").cookie(new NettyCookie("phylo-token", "test-registered-user")), String.class + ); + + HttpClientResponseException e = Assertions.assertThrows(HttpClientResponseException.class, () -> { + HttpResponse response = call.blockingFirst(); + }); + assertEquals(HttpStatus.UNPROCESSABLE_ENTITY, e.getStatus()); + + super.getBrapiDsl().execute(brapiObservationFp.get("DeleteObservations")); } @Test @Order(5) - void revokeProgram() { + void unsubscribeOntologySuccess() { - String url = String.format("/programs/%s/ontology/shared/programs/%s", mainProgram.getId(), otherProgram.getId()); + String url = String.format("/programs/%s/ontology/unsubscribe/%s", otherProgram.getId(), mainProgram.getId()); + Flowable> call = client.exchange( + PUT(url, "").cookie(new NettyCookie("phylo-token", "test-registered-user")), String.class + ); + + HttpResponse response = call.blockingFirst(); + assertEquals(HttpStatus.OK, response.getStatus()); + } + + @Test + @Order(5) + void revokeOntologySuccess() { + + String url = String.format("/programs/%s/ontology/shared/programs/%s", mainProgram.getId(), thirdProgram.getId()); Flowable> call = client.exchange( DELETE(url).cookie(new NettyCookie("phylo-token", "test-registered-user")), String.class ); @@ -354,7 +452,7 @@ void revokeOntologySharedProgramNotExist() { @Test void revokeOntologySharedProgramNotShared() { - String url = String.format("/programs/%s/ontology/shared/programs/%s", mainProgram.getId(), thirdProgram.getId()); + String url = String.format("/programs/%s/ontology/shared/programs/%s", mainProgram.getId(), fourthProgram.getId()); Flowable> call = client.exchange( DELETE(url).cookie(new NettyCookie("phylo-token", "test-registered-user")), String.class ); diff --git a/src/test/resources/sql/brapi/BrAPIOntologyControllerIntegrationTest.sql b/src/test/resources/sql/brapi/BrAPIOntologyControllerIntegrationTest.sql index df07c0dfa..676f7055b 100644 --- a/src/test/resources/sql/brapi/BrAPIOntologyControllerIntegrationTest.sql +++ b/src/test/resources/sql/brapi/BrAPIOntologyControllerIntegrationTest.sql @@ -17,5 +17,20 @@ */ -- name: AddObservations -insert into observation (id, observation_variable_id, value) -select row_number() over (order by id), id, 'test' from observation_variable; \ No newline at end of file +insert into observation (id, observation_variable_id, program_id, value) +select md5(random()::text || clock_timestamp()::text)::uuid, observation_variable.id, matching_program.id, 'test' +from observation_variable +join + ( + select p.id, er.external_reference_id from + "program" p + join + program_external_references per on p.id = per.program_entity_id + join + external_reference er on per.external_references_id = er.id + where + er.external_reference_id = ?::text + ) as matching_program on 1=1; + +-- name: DeleteObservations +delete from observation; \ No newline at end of file From 4744f4b2fe21ee33ffb7e25ff740214ead15cbfe Mon Sep 17 00:00:00 2001 From: Chris T Date: Thu, 31 Mar 2022 09:41:44 -0400 Subject: [PATCH 2/8] subscribe ontology: change unsubscribe to DELETE call --- .../api/v1/controller/OntologyController.java | 2 +- .../v1/controller/OntologyControllerIntegrationTest.java | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/breedinginsight/api/v1/controller/OntologyController.java b/src/main/java/org/breedinginsight/api/v1/controller/OntologyController.java index edaa00552..6dc6dcef0 100644 --- a/src/main/java/org/breedinginsight/api/v1/controller/OntologyController.java +++ b/src/main/java/org/breedinginsight/api/v1/controller/OntologyController.java @@ -165,7 +165,7 @@ public HttpResponse>> subscribeOntology( * @param sharingProgramId -- Program that has shared its ontology. * @return */ - @Put("/programs/{programId}/ontology/unsubscribe/{sharingProgramId}") + @Delete("/programs/{programId}/ontology/subscribe/{sharingProgramId}") @Produces(MediaType.APPLICATION_JSON) @ProgramSecured(roleGroups = {ProgramSecuredRoleGroup.ALL}) public HttpResponse>> unsubscribeOntology( diff --git a/src/test/java/org/breedinginsight/api/v1/controller/OntologyControllerIntegrationTest.java b/src/test/java/org/breedinginsight/api/v1/controller/OntologyControllerIntegrationTest.java index 8e5183549..b81157df6 100644 --- a/src/test/java/org/breedinginsight/api/v1/controller/OntologyControllerIntegrationTest.java +++ b/src/test/java/org/breedinginsight/api/v1/controller/OntologyControllerIntegrationTest.java @@ -364,9 +364,9 @@ void revokeOntologyUneditable() { void unsubscribeOntologyUneditableError() { super.getBrapiDsl().execute(brapiObservationFp.get("AddObservations"), otherProgram.getId().toString()); - String url = String.format("/programs/%s/ontology/unsubscribe/%s", otherProgram.getId(), mainProgram.getId()); + String url = String.format("/programs/%s/ontology/subscribe/%s", otherProgram.getId(), mainProgram.getId()); Flowable> call = client.exchange( - PUT(url, "").cookie(new NettyCookie("phylo-token", "test-registered-user")), String.class + DELETE(url, "").cookie(new NettyCookie("phylo-token", "test-registered-user")), String.class ); HttpClientResponseException e = Assertions.assertThrows(HttpClientResponseException.class, () -> { @@ -381,9 +381,9 @@ void unsubscribeOntologyUneditableError() { @Order(5) void unsubscribeOntologySuccess() { - String url = String.format("/programs/%s/ontology/unsubscribe/%s", otherProgram.getId(), mainProgram.getId()); + String url = String.format("/programs/%s/ontology/subscribe/%s", otherProgram.getId(), mainProgram.getId()); Flowable> call = client.exchange( - PUT(url, "").cookie(new NettyCookie("phylo-token", "test-registered-user")), String.class + DELETE(url, "").cookie(new NettyCookie("phylo-token", "test-registered-user")), String.class ); HttpResponse response = call.blockingFirst(); From bcc8ee77b029946321cb6557aa02504846ffe998 Mon Sep 17 00:00:00 2001 From: Chris T Date: Thu, 31 Mar 2022 09:42:44 -0400 Subject: [PATCH 3/8] subscribe ontology: change permissions to breeder --- .../breedinginsight/api/v1/controller/OntologyController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/breedinginsight/api/v1/controller/OntologyController.java b/src/main/java/org/breedinginsight/api/v1/controller/OntologyController.java index 6dc6dcef0..685615c0e 100644 --- a/src/main/java/org/breedinginsight/api/v1/controller/OntologyController.java +++ b/src/main/java/org/breedinginsight/api/v1/controller/OntologyController.java @@ -145,7 +145,7 @@ public HttpResponse>> revokeOntology( */ @Put("/programs/{programId}/ontology/subscribe/{sharingProgramId}") @Produces(MediaType.APPLICATION_JSON) - @ProgramSecured(roleGroups = {ProgramSecuredRoleGroup.ALL}) + @ProgramSecured(roles = {ProgramSecuredRole.BREEDER}) public HttpResponse>> subscribeOntology( @PathVariable UUID programId, @PathVariable UUID sharingProgramId) { try { @@ -167,7 +167,7 @@ public HttpResponse>> subscribeOntology( */ @Delete("/programs/{programId}/ontology/subscribe/{sharingProgramId}") @Produces(MediaType.APPLICATION_JSON) - @ProgramSecured(roleGroups = {ProgramSecuredRoleGroup.ALL}) + @ProgramSecured(roles = {ProgramSecuredRole.BREEDER}) public HttpResponse>> unsubscribeOntology( @PathVariable UUID programId, @PathVariable UUID sharingProgramId) { try { From 0ffd4ba386e18eb3540e2dd418b26e5257b39fcb Mon Sep 17 00:00:00 2001 From: Chris T Date: Tue, 5 Apr 2022 09:44:17 -0400 Subject: [PATCH 4/8] subscribe ontology: endpoints and fixes --- .../api/v1/controller/OntologyController.java | 65 +++++++++++++++---- .../daos/ProgramOntologyDAO.java | 9 ++- .../org/breedinginsight/daos/TraitDAO.java | 2 + .../model/SubscribedProgram.java | 16 +++++ .../services/OntologyService.java | 52 +++++++++++++-- .../OntologyControllerIntegrationTest.java | 24 +++++++ 6 files changed, 150 insertions(+), 18 deletions(-) create mode 100644 src/main/java/org/breedinginsight/model/SubscribedProgram.java diff --git a/src/main/java/org/breedinginsight/api/v1/controller/OntologyController.java b/src/main/java/org/breedinginsight/api/v1/controller/OntologyController.java index 685615c0e..8e84e5fc7 100644 --- a/src/main/java/org/breedinginsight/api/v1/controller/OntologyController.java +++ b/src/main/java/org/breedinginsight/api/v1/controller/OntologyController.java @@ -20,6 +20,7 @@ import org.breedinginsight.api.model.v1.response.metadata.StatusCode; import org.breedinginsight.api.v1.controller.metadata.AddMetadata; import org.breedinginsight.model.SharedProgram; +import org.breedinginsight.model.SubscribedProgram; import org.breedinginsight.model.Trait; import org.breedinginsight.services.OntologyService; import org.breedinginsight.services.exceptions.DoesNotExistException; @@ -29,6 +30,7 @@ import javax.inject.Inject; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import java.util.UUID; @Slf4j @@ -69,13 +71,17 @@ public OntologyController(SecurityService securityService, OntologyService ontol @ProgramSecured(roles = {ProgramSecuredRole.BREEDER}) public HttpResponse>> getAvailablePrograms( @PathVariable UUID programId, @QueryValue(defaultValue = "false") Boolean shared) { - List sharedPrograms = ontologyService.getSharedOntology(programId, shared); - List metadataStatus = new ArrayList<>(); - metadataStatus.add(new Status(StatusCode.INFO, "Successful Query")); - Pagination pagination = new Pagination(sharedPrograms.size(), 1, 1, 0); - Metadata metadata = new Metadata(pagination, metadataStatus); - Response> response = new Response(metadata, new DataResponse<>(sharedPrograms)); - return HttpResponse.ok(response); + try { + List sharedPrograms = ontologyService.getSharedOntology(programId, shared); + List metadataStatus = new ArrayList<>(); + metadataStatus.add(new Status(StatusCode.INFO, "Successful Query")); + Pagination pagination = new Pagination(sharedPrograms.size(), 1, 1, 0); + Metadata metadata = new Metadata(pagination, metadataStatus); + Response> response = new Response(metadata, new DataResponse<>(sharedPrograms)); + return HttpResponse.ok(response); + } catch (DoesNotExistException e) { + return HttpResponse.status(HttpStatus.NOT_FOUND, e.getMessage()); + } } /** @@ -110,6 +116,8 @@ public HttpResponse>> shareOntology( return response; } catch (UnprocessableEntityException e) { return HttpResponse.status(HttpStatus.UNPROCESSABLE_ENTITY, e.getMessage()); + } catch (DoesNotExistException e) { + return HttpResponse.status(HttpStatus.NOT_FOUND, e.getMessage()); } } @@ -124,7 +132,7 @@ public HttpResponse>> shareOntology( @Delete("/programs/{programId}/ontology/shared/programs/{sharedProgramId}") @Produces(MediaType.APPLICATION_JSON) @ProgramSecured(roles = {ProgramSecuredRole.BREEDER}) - public HttpResponse>> revokeOntology( + public HttpResponse revokeOntology( @PathVariable UUID programId, @PathVariable UUID sharedProgramId) { try { ontologyService.revokeOntology(programId, sharedProgramId); @@ -145,12 +153,14 @@ public HttpResponse>> revokeOntology( */ @Put("/programs/{programId}/ontology/subscribe/{sharingProgramId}") @Produces(MediaType.APPLICATION_JSON) + @AddMetadata @ProgramSecured(roles = {ProgramSecuredRole.BREEDER}) - public HttpResponse>> subscribeOntology( + public HttpResponse> subscribeOntology( @PathVariable UUID programId, @PathVariable UUID sharingProgramId) { try { - ontologyService.subscribeOntology(programId, sharingProgramId); - return HttpResponse.ok(); + SubscribedProgram shareRequest = ontologyService.subscribeOntology(programId, sharingProgramId); + Response response = new Response(shareRequest); + return HttpResponse.ok(response); } catch (UnprocessableEntityException e) { return HttpResponse.status(HttpStatus.UNPROCESSABLE_ENTITY, e.getMessage()); } catch (DoesNotExistException e) { @@ -168,7 +178,7 @@ public HttpResponse>> subscribeOntology( @Delete("/programs/{programId}/ontology/subscribe/{sharingProgramId}") @Produces(MediaType.APPLICATION_JSON) @ProgramSecured(roles = {ProgramSecuredRole.BREEDER}) - public HttpResponse>> unsubscribeOntology( + public HttpResponse unsubscribeOntology( @PathVariable UUID programId, @PathVariable UUID sharingProgramId) { try { ontologyService.unsubscribeOntology(programId, sharingProgramId); @@ -179,4 +189,35 @@ public HttpResponse>> unsubscribeOntology( return HttpResponse.status(HttpStatus.NOT_FOUND, e.getMessage()); } } + + /** + * Retrieves subscription options for programs that have shared their ontology with the requesting program. + * Will indicate whether the program has subscribed to a given ontology or not. + * + * @param programId -- Program request information + * @return + * { + * programId, -- Program that owns the ontology the request program is subscribed to. + * programName, + * subscribed -- boolean. Whether the requesting program is subscribed to this ontology or not. + * } + */ + @Get("/programs/{programId}/ontology/subscribe") + @Produces(MediaType.APPLICATION_JSON) + @AddMetadata + @ProgramSecured(roles = {ProgramSecuredRole.BREEDER}) + public HttpResponse>> getSubscribedOntology( + @PathVariable UUID programId) { + try { + List shareRequests = ontologyService.getSubscribeOntologyOptions(programId); + List metadataStatus = new ArrayList<>(); + metadataStatus.add(new Status(StatusCode.INFO, "Successful Creation")); + Pagination pagination = new Pagination(shareRequests.size(), 1, 1, 0); + Metadata metadata = new Metadata(pagination, metadataStatus); + Response> response = new Response(metadata, new DataResponse<>(shareRequests)); + return HttpResponse.ok(response); + } catch (DoesNotExistException e) { + return HttpResponse.status(HttpStatus.NOT_FOUND, e.getMessage()); + } + } } diff --git a/src/main/java/org/breedinginsight/daos/ProgramOntologyDAO.java b/src/main/java/org/breedinginsight/daos/ProgramOntologyDAO.java index b72af5c84..0a437f9e6 100644 --- a/src/main/java/org/breedinginsight/daos/ProgramOntologyDAO.java +++ b/src/main/java/org/breedinginsight/daos/ProgramOntologyDAO.java @@ -66,7 +66,10 @@ public void revokeSharedOntology(ProgramSharedOntologyEntity sharedOntology) { } public Optional getSubscribedSharedOntology(UUID programId) { - List shareRecords = programSharedOntologyDao.fetchBySharedProgramId(programId); + List shareRecords = programSharedOntologyDao.fetchBySharedProgramId(programId).stream() + .filter(shareRecord -> shareRecord.getActive()) + .collect(Collectors.toList()); + return shareRecords.size() > 0 ? Optional.of(shareRecords.get(0)) : Optional.empty(); } @@ -79,4 +82,8 @@ public void denySharedOntology(ProgramSharedOntologyEntity sharedOntology) { sharedOntology.setActive(false); programSharedOntologyDao.update(sharedOntology); } + + public List getSubscriptionOptions(UUID programId) { + return programSharedOntologyDao.fetchBySharedProgramId(programId); + } } diff --git a/src/main/java/org/breedinginsight/daos/TraitDAO.java b/src/main/java/org/breedinginsight/daos/TraitDAO.java index f04afa546..fdf75e50f 100644 --- a/src/main/java/org/breedinginsight/daos/TraitDAO.java +++ b/src/main/java/org/breedinginsight/daos/TraitDAO.java @@ -238,6 +238,8 @@ public List getObservationsForTraitsByBrAPIProgram(String brap } public List searchVariables(List variableIds) { + + if (variableIds == null || variableIds.size() == 0) return new ArrayList<>(); try { BrAPIObservationVariableSearchRequest request = new BrAPIObservationVariableSearchRequest() .externalReferenceIDs(variableIds); diff --git a/src/main/java/org/breedinginsight/model/SubscribedProgram.java b/src/main/java/org/breedinginsight/model/SubscribedProgram.java new file mode 100644 index 000000000..812ec9975 --- /dev/null +++ b/src/main/java/org/breedinginsight/model/SubscribedProgram.java @@ -0,0 +1,16 @@ +package org.breedinginsight.model; + +import lombok.*; + +import java.util.UUID; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class SubscribedProgram { + private UUID programId; + private String programName; + private Boolean subscribed; +} diff --git a/src/main/java/org/breedinginsight/services/OntologyService.java b/src/main/java/org/breedinginsight/services/OntologyService.java index 75317435a..cb6caa9ef 100644 --- a/src/main/java/org/breedinginsight/services/OntologyService.java +++ b/src/main/java/org/breedinginsight/services/OntologyService.java @@ -14,6 +14,7 @@ import org.breedinginsight.daos.TraitDAO; import org.breedinginsight.model.Program; import org.breedinginsight.model.SharedProgram; +import org.breedinginsight.model.SubscribedProgram; import org.breedinginsight.model.Trait; import org.breedinginsight.services.exceptions.DoesNotExistException; import org.breedinginsight.services.exceptions.UnprocessableEntityException; @@ -47,7 +48,7 @@ public OntologyService(ProgramDAO programDAO, ProgramOntologyDAO programOntology * @param sharedOnly -- True = return only shared programs, False = get all shareable programs * @return List */ - public List getSharedOntology(@NotNull UUID programId, @NotNull Boolean sharedOnly) { + public List getSharedOntology(@NotNull UUID programId, @NotNull Boolean sharedOnly) throws DoesNotExistException { // Get program with that id Program program = getProgram(programId); @@ -101,10 +102,10 @@ private List getMatchingPrograms(Program program) { return matchingPrograms; } - private Program getProgram(UUID programId) { + private Program getProgram(UUID programId) throws DoesNotExistException { List programs = programDAO.get(programId); if (programs.size() == 0) { - throw new HttpStatusException(HttpStatus.NOT_FOUND, "Program with that id does not exist"); + throw new DoesNotExistException("Program with that id does not exist"); } return programs.get(0); } @@ -157,7 +158,7 @@ private Boolean ontologyIsEditable(ProgramSharedOntologyEntity sharedOntologyEnt * @param programRequests -- List of programs to share ontology with * @return List */ - public List shareOntology(@NotNull UUID programId, AuthenticatedUser actingUser, List programRequests) throws ValidatorException, UnprocessableEntityException { + public List shareOntology(@NotNull UUID programId, AuthenticatedUser actingUser, List programRequests) throws ValidatorException, UnprocessableEntityException, DoesNotExistException { // Get program with that id Program program = getProgram(programId); @@ -241,7 +242,7 @@ public void revokeOntology(@NotNull UUID programId, @NotNull UUID sharedProgramI programOntologyDAO.revokeSharedOntology(sharedOntology); } - public void subscribeOntology(UUID programId, UUID sharingProgramId) throws DoesNotExistException, UnprocessableEntityException { + public SubscribedProgram subscribeOntology(UUID programId, UUID sharingProgramId) throws DoesNotExistException, UnprocessableEntityException { // Check that program exists Program program = getProgram(programId); @@ -258,8 +259,29 @@ public void subscribeOntology(UUID programId, UUID sharingProgramId) throws Does throw new UnprocessableEntityException("Program already has traits, cannot subscribe to a shared ontology"); } + // Check that program does not have any current shares of its own ontology + List sharedOntologies = programOntologyDAO.getSharedOntologies(program.getId()); + if (!sharedOntologies.isEmpty()) { + throw new UnprocessableEntityException("Program has shared its ontology with other programs, cannot subscribe to another ontology."); + } + + // Subscribe programOntologyDAO.acceptSharedOntology(sharedOntology); + + // Get the subscription record + try { + List subscribedProgramOptions = getSubscribeOntologyOptions(programId); + for (SubscribedProgram option: subscribedProgramOptions) { + if (option.getProgramId().equals(sharingProgramId)) { + return option; + } + } + } catch (DoesNotExistException e) { + throw new InternalServerException("Recently subscribed program cannot be found."); + } + + throw new InternalServerException("Recently subscribed program cannot be found."); } public void unsubscribeOntology(UUID programId, UUID sharingProgramId) throws DoesNotExistException, UnprocessableEntityException { @@ -280,4 +302,24 @@ public void unsubscribeOntology(UUID programId, UUID sharingProgramId) throws Do // Subscribe programOntologyDAO.denySharedOntology(sharedOntology); } + + public List getSubscribeOntologyOptions(UUID programId) throws DoesNotExistException { + + Program program = getProgram(programId); + + List sharedOntologies = programOntologyDAO.getSubscriptionOptions(programId); + List programs = programDAO.get(sharedOntologies.stream().map(ProgramSharedOntologyEntity::getProgramId).collect(Collectors.toList())); + Map programMap = new HashMap<>(); + programs.forEach(sharedProgram -> programMap.put(sharedProgram.getId(), sharedProgram)); + + List subscriptionOptions = sharedOntologies.stream() + .map(sharedOntology -> SubscribedProgram.builder() + .programId(sharedOntology.getProgramId()) + .programName(programMap.get(sharedOntology.getProgramId()).getName()) + .subscribed(sharedOntology.getActive()) + .build() + ).collect(Collectors.toList()); + return subscriptionOptions; + } + } diff --git a/src/test/java/org/breedinginsight/api/v1/controller/OntologyControllerIntegrationTest.java b/src/test/java/org/breedinginsight/api/v1/controller/OntologyControllerIntegrationTest.java index b81157df6..b8f3f271a 100644 --- a/src/test/java/org/breedinginsight/api/v1/controller/OntologyControllerIntegrationTest.java +++ b/src/test/java/org/breedinginsight/api/v1/controller/OntologyControllerIntegrationTest.java @@ -263,6 +263,30 @@ void subscribeOntologySuccess() { assertEquals(HttpStatus.OK, response.getStatus()); } + @Test + @Order(4) + void getSubscribedOntologyOptions() { + + String url = String.format("/programs/%s/ontology/subscribe", otherProgram.getId()); + Flowable> call = client.exchange( + GET(url).cookie(new NettyCookie("phylo-token", "test-registered-user")), String.class + ); + + HttpResponse response = call.blockingFirst(); + assertEquals(HttpStatus.OK, response.getStatus()); + + JsonObject result = JsonParser.parseString(response.body()).getAsJsonObject().getAsJsonObject("result"); + JsonArray data = result.getAsJsonArray("data"); + assertEquals(1, data.size(), "Wrong number of programs returned"); + + // Check all are not shared and are inactive + for (JsonElement element: data) { + JsonObject program = element.getAsJsonObject(); + + assertTrue(program.get("subscribed").getAsBoolean()); + } + } + @Test @Order(4) void getAllProgramsSharedPrograms() { From 697649ed303b675bee05dabe24d21d4578a699fb Mon Sep 17 00:00:00 2001 From: Chris T Date: Wed, 6 Apr 2022 10:08:44 -0400 Subject: [PATCH 5/8] subscribe ontology: add editable trait to subscribe options endpoint --- .../breedinginsight/api/v1/controller/OntologyController.java | 3 ++- src/main/java/org/breedinginsight/model/SubscribedProgram.java | 1 + .../java/org/breedinginsight/services/OntologyService.java | 1 + .../api/v1/controller/OntologyControllerIntegrationTest.java | 1 + 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/breedinginsight/api/v1/controller/OntologyController.java b/src/main/java/org/breedinginsight/api/v1/controller/OntologyController.java index 8e84e5fc7..56e0ac7db 100644 --- a/src/main/java/org/breedinginsight/api/v1/controller/OntologyController.java +++ b/src/main/java/org/breedinginsight/api/v1/controller/OntologyController.java @@ -199,7 +199,8 @@ public HttpResponse unsubscribeOntology( * { * programId, -- Program that owns the ontology the request program is subscribed to. * programName, - * subscribed -- boolean. Whether the requesting program is subscribed to this ontology or not. + * subscribed, -- boolean. Whether the requesting program is subscribed to this ontology or not. + * editable -- boolean || null. Indicates whether this program can unsubscribe from this ontology or not. Null if not subscribed to this ontology. * } */ @Get("/programs/{programId}/ontology/subscribe") diff --git a/src/main/java/org/breedinginsight/model/SubscribedProgram.java b/src/main/java/org/breedinginsight/model/SubscribedProgram.java index 812ec9975..ddde9c650 100644 --- a/src/main/java/org/breedinginsight/model/SubscribedProgram.java +++ b/src/main/java/org/breedinginsight/model/SubscribedProgram.java @@ -13,4 +13,5 @@ public class SubscribedProgram { private UUID programId; private String programName; private Boolean subscribed; + private Boolean editable; } diff --git a/src/main/java/org/breedinginsight/services/OntologyService.java b/src/main/java/org/breedinginsight/services/OntologyService.java index cb6caa9ef..efdea3846 100644 --- a/src/main/java/org/breedinginsight/services/OntologyService.java +++ b/src/main/java/org/breedinginsight/services/OntologyService.java @@ -317,6 +317,7 @@ public List getSubscribeOntologyOptions(UUID programId) throw .programId(sharedOntology.getProgramId()) .programName(programMap.get(sharedOntology.getProgramId()).getName()) .subscribed(sharedOntology.getActive()) + .editable(sharedOntology.getActive() ? ontologyIsEditable(sharedOntology) : null) .build() ).collect(Collectors.toList()); return subscriptionOptions; diff --git a/src/test/java/org/breedinginsight/api/v1/controller/OntologyControllerIntegrationTest.java b/src/test/java/org/breedinginsight/api/v1/controller/OntologyControllerIntegrationTest.java index b8f3f271a..3f43ab3ad 100644 --- a/src/test/java/org/breedinginsight/api/v1/controller/OntologyControllerIntegrationTest.java +++ b/src/test/java/org/breedinginsight/api/v1/controller/OntologyControllerIntegrationTest.java @@ -284,6 +284,7 @@ void getSubscribedOntologyOptions() { JsonObject program = element.getAsJsonObject(); assertTrue(program.get("subscribed").getAsBoolean()); + assertTrue(program.get("editable").getAsBoolean()); } } From ddfa722a366912ebe5fd97de4702a1e476dd0fe4 Mon Sep 17 00:00:00 2001 From: Chris T Date: Mon, 11 Apr 2022 10:08:00 -0400 Subject: [PATCH 6/8] subscribe ontology: rename models --- .../model/{SharedProgram.java => SharedOntology.java} | 0 .../model/{SubscribedProgram.java => SubscribedOntology.java} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/org/breedinginsight/model/{SharedProgram.java => SharedOntology.java} (100%) rename src/main/java/org/breedinginsight/model/{SubscribedProgram.java => SubscribedOntology.java} (100%) diff --git a/src/main/java/org/breedinginsight/model/SharedProgram.java b/src/main/java/org/breedinginsight/model/SharedOntology.java similarity index 100% rename from src/main/java/org/breedinginsight/model/SharedProgram.java rename to src/main/java/org/breedinginsight/model/SharedOntology.java diff --git a/src/main/java/org/breedinginsight/model/SubscribedProgram.java b/src/main/java/org/breedinginsight/model/SubscribedOntology.java similarity index 100% rename from src/main/java/org/breedinginsight/model/SubscribedProgram.java rename to src/main/java/org/breedinginsight/model/SubscribedOntology.java From 10cba5703056389dfe7fe264198356592b34291e Mon Sep 17 00:00:00 2001 From: Chris T Date: Mon, 11 Apr 2022 10:08:19 -0400 Subject: [PATCH 7/8] subscribe ontology: PR changes --- .../api/v1/controller/OntologyController.java | 51 ++++++++++--------- .../daos/ProgramOntologyDAO.java | 3 -- .../breedinginsight/model/SharedOntology.java | 2 +- .../model/SubscribedOntology.java | 2 +- .../services/OntologyService.java | 35 +++++++------ .../OntologyControllerIntegrationTest.java | 6 --- 6 files changed, 47 insertions(+), 52 deletions(-) diff --git a/src/main/java/org/breedinginsight/api/v1/controller/OntologyController.java b/src/main/java/org/breedinginsight/api/v1/controller/OntologyController.java index 56e0ac7db..6d5681143 100644 --- a/src/main/java/org/breedinginsight/api/v1/controller/OntologyController.java +++ b/src/main/java/org/breedinginsight/api/v1/controller/OntologyController.java @@ -4,12 +4,9 @@ import io.micronaut.http.HttpStatus; import io.micronaut.http.MediaType; import io.micronaut.http.annotation.*; -import io.micronaut.security.annotation.Secured; -import io.micronaut.security.rules.SecurityRule; import lombok.extern.slf4j.Slf4j; import org.breedinginsight.api.auth.ProgramSecured; import org.breedinginsight.api.auth.ProgramSecuredRole; -import org.breedinginsight.api.auth.ProgramSecuredRoleGroup; import org.breedinginsight.api.auth.SecurityService; import org.breedinginsight.api.model.v1.request.SharedOntologyProgramRequest; import org.breedinginsight.api.model.v1.response.DataResponse; @@ -19,9 +16,8 @@ import org.breedinginsight.api.model.v1.response.metadata.Status; import org.breedinginsight.api.model.v1.response.metadata.StatusCode; import org.breedinginsight.api.v1.controller.metadata.AddMetadata; -import org.breedinginsight.model.SharedProgram; -import org.breedinginsight.model.SubscribedProgram; -import org.breedinginsight.model.Trait; +import org.breedinginsight.model.SharedOntology; +import org.breedinginsight.model.SubscribedOntology; import org.breedinginsight.services.OntologyService; import org.breedinginsight.services.exceptions.DoesNotExistException; import org.breedinginsight.services.exceptions.UnprocessableEntityException; @@ -30,7 +26,6 @@ import javax.inject.Inject; import java.util.ArrayList; import java.util.List; -import java.util.Optional; import java.util.UUID; @Slf4j @@ -69,17 +64,18 @@ public OntologyController(SecurityService securityService, OntologyService ontol @Produces(MediaType.APPLICATION_JSON) @AddMetadata @ProgramSecured(roles = {ProgramSecuredRole.BREEDER}) - public HttpResponse>> getAvailablePrograms( + public HttpResponse>> getAvailablePrograms( @PathVariable UUID programId, @QueryValue(defaultValue = "false") Boolean shared) { try { - List sharedPrograms = ontologyService.getSharedOntology(programId, shared); - List metadataStatus = new ArrayList<>(); + List sharedOntologies = ontologyService.getSharedOntology(programId, shared); + List metadataStatus = new ArrayList<>(); metadataStatus.add(new Status(StatusCode.INFO, "Successful Query")); - Pagination pagination = new Pagination(sharedPrograms.size(), 1, 1, 0); + Pagination pagination = new Pagination(sharedOntologies.size(), 1, 1, 0); Metadata metadata = new Metadata(pagination, metadataStatus); - Response> response = new Response(metadata, new DataResponse<>(sharedPrograms)); + Response> response = new Response(metadata, new DataResponse<>(sharedOntologies)); return HttpResponse.ok(response); } catch (DoesNotExistException e) { + log.error(e.getMessage()); return HttpResponse.status(HttpStatus.NOT_FOUND, e.getMessage()); } } @@ -100,23 +96,25 @@ public HttpResponse>> getAvailablePrograms( @Post("/programs/{programId}/ontology/shared/programs") @Produces(MediaType.APPLICATION_JSON) @ProgramSecured(roles = {ProgramSecuredRole.BREEDER}) - public HttpResponse>> shareOntology( + public HttpResponse>> shareOntology( @PathVariable UUID programId, @Body List request) { try { - List sharedPrograms = ontologyService.shareOntology(programId, securityService.getUser(), request); - List metadataStatus = new ArrayList<>(); + List sharedOntologies = ontologyService.shareOntology(programId, securityService.getUser(), request); + List metadataStatus = new ArrayList<>(); metadataStatus.add(new Status(StatusCode.INFO, "Successful Creation")); - Pagination pagination = new Pagination(sharedPrograms.size(), 1, 1, 0); + Pagination pagination = new Pagination(sharedOntologies.size(), 1, 1, 0); Metadata metadata = new Metadata(pagination, metadataStatus); - Response> response = new Response(metadata, new DataResponse<>(sharedPrograms)); + Response> response = new Response(metadata, new DataResponse<>(sharedOntologies)); return HttpResponse.ok(response); } catch (ValidatorException e) { log.error("Validation errors", e); HttpResponse response = HttpResponse.status(HttpStatus.UNPROCESSABLE_ENTITY).body(e.getErrors()); return response; } catch (UnprocessableEntityException e) { + log.error(e.getMessage()); return HttpResponse.status(HttpStatus.UNPROCESSABLE_ENTITY, e.getMessage()); } catch (DoesNotExistException e) { + log.error(e.getMessage()); return HttpResponse.status(HttpStatus.NOT_FOUND, e.getMessage()); } } @@ -138,8 +136,10 @@ public HttpResponse revokeOntology( ontologyService.revokeOntology(programId, sharedProgramId); return HttpResponse.ok(); } catch (UnprocessableEntityException e) { + log.error(e.getMessage()); return HttpResponse.status(HttpStatus.UNPROCESSABLE_ENTITY, e.getMessage()); } catch (DoesNotExistException e) { + log.error(e.getMessage()); return HttpResponse.status(HttpStatus.NOT_FOUND, e.getMessage()); } } @@ -155,15 +155,17 @@ public HttpResponse revokeOntology( @Produces(MediaType.APPLICATION_JSON) @AddMetadata @ProgramSecured(roles = {ProgramSecuredRole.BREEDER}) - public HttpResponse> subscribeOntology( + public HttpResponse> subscribeOntology( @PathVariable UUID programId, @PathVariable UUID sharingProgramId) { try { - SubscribedProgram shareRequest = ontologyService.subscribeOntology(programId, sharingProgramId); - Response response = new Response(shareRequest); + SubscribedOntology shareRequest = ontologyService.subscribeOntology(programId, sharingProgramId); + Response response = new Response(shareRequest); return HttpResponse.ok(response); } catch (UnprocessableEntityException e) { + log.error(e.getMessage()); return HttpResponse.status(HttpStatus.UNPROCESSABLE_ENTITY, e.getMessage()); } catch (DoesNotExistException e) { + log.error(e.getMessage()); return HttpResponse.status(HttpStatus.NOT_FOUND, e.getMessage()); } } @@ -184,8 +186,10 @@ public HttpResponse unsubscribeOntology( ontologyService.unsubscribeOntology(programId, sharingProgramId); return HttpResponse.ok(); } catch (UnprocessableEntityException e) { + log.error(e.getMessage()); return HttpResponse.status(HttpStatus.UNPROCESSABLE_ENTITY, e.getMessage()); } catch (DoesNotExistException e) { + log.error(e.getMessage()); return HttpResponse.status(HttpStatus.NOT_FOUND, e.getMessage()); } } @@ -207,17 +211,18 @@ public HttpResponse unsubscribeOntology( @Produces(MediaType.APPLICATION_JSON) @AddMetadata @ProgramSecured(roles = {ProgramSecuredRole.BREEDER}) - public HttpResponse>> getSubscribedOntology( + public HttpResponse>> getSubscribedOntology( @PathVariable UUID programId) { try { - List shareRequests = ontologyService.getSubscribeOntologyOptions(programId); + List shareRequests = ontologyService.getSubscribeOntologyOptions(programId); List metadataStatus = new ArrayList<>(); metadataStatus.add(new Status(StatusCode.INFO, "Successful Creation")); Pagination pagination = new Pagination(shareRequests.size(), 1, 1, 0); Metadata metadata = new Metadata(pagination, metadataStatus); - Response> response = new Response(metadata, new DataResponse<>(shareRequests)); + Response> response = new Response(metadata, new DataResponse<>(shareRequests)); return HttpResponse.ok(response); } catch (DoesNotExistException e) { + log.error(e.getMessage()); return HttpResponse.status(HttpStatus.NOT_FOUND, e.getMessage()); } } diff --git a/src/main/java/org/breedinginsight/daos/ProgramOntologyDAO.java b/src/main/java/org/breedinginsight/daos/ProgramOntologyDAO.java index 0a437f9e6..3d11e6518 100644 --- a/src/main/java/org/breedinginsight/daos/ProgramOntologyDAO.java +++ b/src/main/java/org/breedinginsight/daos/ProgramOntologyDAO.java @@ -20,14 +20,11 @@ import org.breedinginsight.dao.db.tables.daos.ProgramOntologyDao; import org.breedinginsight.dao.db.tables.daos.ProgramSharedOntologyDao; import org.breedinginsight.dao.db.tables.pojos.ProgramSharedOntologyEntity; -import org.breedinginsight.model.ProgramOntology; import org.jooq.Configuration; import org.jooq.DSLContext; import javax.inject.Inject; import javax.inject.Singleton; -import javax.swing.text.html.Option; -import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.UUID; diff --git a/src/main/java/org/breedinginsight/model/SharedOntology.java b/src/main/java/org/breedinginsight/model/SharedOntology.java index 24c12f0ea..54cfc12d6 100644 --- a/src/main/java/org/breedinginsight/model/SharedOntology.java +++ b/src/main/java/org/breedinginsight/model/SharedOntology.java @@ -9,7 +9,7 @@ @Builder @AllArgsConstructor @NoArgsConstructor -public class SharedProgram { +public class SharedOntology { private UUID programId; private String programName; private Boolean shared; diff --git a/src/main/java/org/breedinginsight/model/SubscribedOntology.java b/src/main/java/org/breedinginsight/model/SubscribedOntology.java index ddde9c650..54c664e85 100644 --- a/src/main/java/org/breedinginsight/model/SubscribedOntology.java +++ b/src/main/java/org/breedinginsight/model/SubscribedOntology.java @@ -9,7 +9,7 @@ @NoArgsConstructor @AllArgsConstructor @Builder -public class SubscribedProgram { +public class SubscribedOntology { private UUID programId; private String programName; private Boolean subscribed; diff --git a/src/main/java/org/breedinginsight/services/OntologyService.java b/src/main/java/org/breedinginsight/services/OntologyService.java index efdea3846..b4687a1cd 100644 --- a/src/main/java/org/breedinginsight/services/OntologyService.java +++ b/src/main/java/org/breedinginsight/services/OntologyService.java @@ -1,7 +1,6 @@ package org.breedinginsight.services; import io.micronaut.http.HttpStatus; -import io.micronaut.http.exceptions.HttpStatusException; import io.micronaut.http.server.exceptions.InternalServerException; import org.brapi.v2.model.core.BrAPIProgram; import org.breedinginsight.api.auth.AuthenticatedUser; @@ -13,8 +12,8 @@ import org.breedinginsight.daos.ProgramOntologyDAO; import org.breedinginsight.daos.TraitDAO; import org.breedinginsight.model.Program; -import org.breedinginsight.model.SharedProgram; -import org.breedinginsight.model.SubscribedProgram; +import org.breedinginsight.model.SharedOntology; +import org.breedinginsight.model.SubscribedOntology; import org.breedinginsight.model.Trait; import org.breedinginsight.services.exceptions.DoesNotExistException; import org.breedinginsight.services.exceptions.UnprocessableEntityException; @@ -53,8 +52,8 @@ public List getSharedOntology(@NotNull UUID programId, @NotNull Boolean sharedOn // Get program with that id Program program = getProgram(programId); - List formattedPrograms = getSharedProgramsFormatted(program); - Set sharedProgramIds = formattedPrograms.stream().map(SharedProgram::getProgramId).collect(Collectors.toSet()); + List formattedPrograms = getSharedProgramsFormatted(program); + Set sharedProgramIds = formattedPrograms.stream().map(SharedOntology::getProgramId).collect(Collectors.toSet()); // Add other programs if (!sharedOnly) { @@ -69,7 +68,7 @@ public List getSharedOntology(@NotNull UUID programId, @NotNull Boolean sharedOn return formattedPrograms; } - private List getSharedProgramsFormatted(Program program) { + private List getSharedProgramsFormatted(Program program) { // Get shared ontology records List sharedOntologies = programOntologyDAO.getSharedOntologies(program.getId()); // Get the programs ontology is shared with @@ -110,8 +109,8 @@ private Program getProgram(UUID programId) throws DoesNotExistException { return programs.get(0); } - private SharedProgram formatResponse(Program program, ProgramSharedOntologyEntity programSharedOntologyEntity, Boolean editable) { - return SharedProgram.builder() + private SharedOntology formatResponse(Program program, ProgramSharedOntologyEntity programSharedOntologyEntity, Boolean editable) { + return SharedOntology.builder() .programId(program.getId()) .programName(program.getName()) .shared(true) @@ -120,8 +119,8 @@ private SharedProgram formatResponse(Program program, ProgramSharedOntologyEntit .build(); } - private SharedProgram formatResponse(Program program) { - return SharedProgram.builder() + private SharedOntology formatResponse(Program program) { + return SharedOntology.builder() .programId(program.getId()) .programName(program.getName()) .shared(false) @@ -158,7 +157,7 @@ private Boolean ontologyIsEditable(ProgramSharedOntologyEntity sharedOntologyEnt * @param programRequests -- List of programs to share ontology with * @return List */ - public List shareOntology(@NotNull UUID programId, AuthenticatedUser actingUser, List programRequests) throws ValidatorException, UnprocessableEntityException, DoesNotExistException { + public List shareOntology(@NotNull UUID programId, AuthenticatedUser actingUser, List programRequests) throws ValidatorException, UnprocessableEntityException, DoesNotExistException { // Get program with that id Program program = getProgram(programId); @@ -213,7 +212,7 @@ public List shareOntology(@NotNull UUID programId, AuthenticatedU // Query return data return getSharedProgramsFormatted(program).stream() - .filter(sharedProgram -> shareProgramIdsSet.contains(sharedProgram.getProgramId())) + .filter(sharedOntology -> shareProgramIdsSet.contains(sharedOntology.getProgramId())) .collect(Collectors.toList()); } @@ -242,7 +241,7 @@ public void revokeOntology(@NotNull UUID programId, @NotNull UUID sharedProgramI programOntologyDAO.revokeSharedOntology(sharedOntology); } - public SubscribedProgram subscribeOntology(UUID programId, UUID sharingProgramId) throws DoesNotExistException, UnprocessableEntityException { + public SubscribedOntology subscribeOntology(UUID programId, UUID sharingProgramId) throws DoesNotExistException, UnprocessableEntityException { // Check that program exists Program program = getProgram(programId); @@ -271,8 +270,8 @@ public SubscribedProgram subscribeOntology(UUID programId, UUID sharingProgramId // Get the subscription record try { - List subscribedProgramOptions = getSubscribeOntologyOptions(programId); - for (SubscribedProgram option: subscribedProgramOptions) { + List subscribedOntologyOptions = getSubscribeOntologyOptions(programId); + for (SubscribedOntology option: subscribedOntologyOptions) { if (option.getProgramId().equals(sharingProgramId)) { return option; } @@ -303,7 +302,7 @@ public void unsubscribeOntology(UUID programId, UUID sharingProgramId) throws Do programOntologyDAO.denySharedOntology(sharedOntology); } - public List getSubscribeOntologyOptions(UUID programId) throws DoesNotExistException { + public List getSubscribeOntologyOptions(UUID programId) throws DoesNotExistException { Program program = getProgram(programId); @@ -312,8 +311,8 @@ public List getSubscribeOntologyOptions(UUID programId) throw Map programMap = new HashMap<>(); programs.forEach(sharedProgram -> programMap.put(sharedProgram.getId(), sharedProgram)); - List subscriptionOptions = sharedOntologies.stream() - .map(sharedOntology -> SubscribedProgram.builder() + List subscriptionOptions = sharedOntologies.stream() + .map(sharedOntology -> SubscribedOntology.builder() .programId(sharedOntology.getProgramId()) .programName(programMap.get(sharedOntology.getProgramId()).getName()) .subscribed(sharedOntology.getActive()) diff --git a/src/test/java/org/breedinginsight/api/v1/controller/OntologyControllerIntegrationTest.java b/src/test/java/org/breedinginsight/api/v1/controller/OntologyControllerIntegrationTest.java index 3f43ab3ad..82195581c 100644 --- a/src/test/java/org/breedinginsight/api/v1/controller/OntologyControllerIntegrationTest.java +++ b/src/test/java/org/breedinginsight/api/v1/controller/OntologyControllerIntegrationTest.java @@ -11,11 +11,7 @@ import io.micronaut.http.netty.cookies.NettyCookie; import io.micronaut.test.annotation.MicronautTest; import io.reactivex.Flowable; -import org.brapi.v2.model.core.BrAPIProgram; -import org.brapi.v2.model.pheno.BrAPIObservation; -import org.brapi.v2.model.pheno.BrAPIObservationVariable; import org.breedinginsight.BrAPITest; -import org.breedinginsight.DatabaseTest; import org.breedinginsight.TestUtils; import org.breedinginsight.api.model.v1.request.ProgramRequest; import org.breedinginsight.api.model.v1.request.SharedOntologyProgramRequest; @@ -26,7 +22,6 @@ import org.breedinginsight.daos.SpeciesDAO; import org.breedinginsight.daos.UserDAO; import org.breedinginsight.model.*; -import org.breedinginsight.services.exceptions.UnprocessableEntityException; import org.jooq.DSLContext; import org.junit.jupiter.api.*; @@ -35,7 +30,6 @@ import java.time.OffsetDateTime; import java.util.ArrayList; import java.util.List; -import java.util.Map; import java.util.UUID; import static io.micronaut.http.HttpRequest.*; From dae560449125bfae1c93220f7fcb0b474a732392 Mon Sep 17 00:00:00 2001 From: Chris T Date: Tue, 19 Apr 2022 09:49:14 -0400 Subject: [PATCH 8/8] subscribe ontology: add error to logging --- .../api/v1/controller/OntologyController.java | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/breedinginsight/api/v1/controller/OntologyController.java b/src/main/java/org/breedinginsight/api/v1/controller/OntologyController.java index 6d5681143..d6b0e6a5d 100644 --- a/src/main/java/org/breedinginsight/api/v1/controller/OntologyController.java +++ b/src/main/java/org/breedinginsight/api/v1/controller/OntologyController.java @@ -75,7 +75,7 @@ public HttpResponse>> getAvailablePrograms Response> response = new Response(metadata, new DataResponse<>(sharedOntologies)); return HttpResponse.ok(response); } catch (DoesNotExistException e) { - log.error(e.getMessage()); + log.error(e.getMessage(), e); return HttpResponse.status(HttpStatus.NOT_FOUND, e.getMessage()); } } @@ -111,10 +111,10 @@ public HttpResponse>> shareOntology( HttpResponse response = HttpResponse.status(HttpStatus.UNPROCESSABLE_ENTITY).body(e.getErrors()); return response; } catch (UnprocessableEntityException e) { - log.error(e.getMessage()); + log.error(e.getMessage(), e); return HttpResponse.status(HttpStatus.UNPROCESSABLE_ENTITY, e.getMessage()); } catch (DoesNotExistException e) { - log.error(e.getMessage()); + log.error(e.getMessage(), e); return HttpResponse.status(HttpStatus.NOT_FOUND, e.getMessage()); } } @@ -136,10 +136,10 @@ public HttpResponse revokeOntology( ontologyService.revokeOntology(programId, sharedProgramId); return HttpResponse.ok(); } catch (UnprocessableEntityException e) { - log.error(e.getMessage()); + log.error(e.getMessage(), e); return HttpResponse.status(HttpStatus.UNPROCESSABLE_ENTITY, e.getMessage()); } catch (DoesNotExistException e) { - log.error(e.getMessage()); + log.error(e.getMessage(), e); return HttpResponse.status(HttpStatus.NOT_FOUND, e.getMessage()); } } @@ -162,10 +162,10 @@ public HttpResponse> subscribeOntology( Response response = new Response(shareRequest); return HttpResponse.ok(response); } catch (UnprocessableEntityException e) { - log.error(e.getMessage()); + log.error(e.getMessage(), e); return HttpResponse.status(HttpStatus.UNPROCESSABLE_ENTITY, e.getMessage()); } catch (DoesNotExistException e) { - log.error(e.getMessage()); + log.error(e.getMessage(), e); return HttpResponse.status(HttpStatus.NOT_FOUND, e.getMessage()); } } @@ -186,10 +186,10 @@ public HttpResponse unsubscribeOntology( ontologyService.unsubscribeOntology(programId, sharingProgramId); return HttpResponse.ok(); } catch (UnprocessableEntityException e) { - log.error(e.getMessage()); + log.error(e.getMessage(), e); return HttpResponse.status(HttpStatus.UNPROCESSABLE_ENTITY, e.getMessage()); } catch (DoesNotExistException e) { - log.error(e.getMessage()); + log.error(e.getMessage(), e); return HttpResponse.status(HttpStatus.NOT_FOUND, e.getMessage()); } } @@ -222,7 +222,7 @@ public HttpResponse>> getSubscribedOnt Response> response = new Response(metadata, new DataResponse<>(shareRequests)); return HttpResponse.ok(response); } catch (DoesNotExistException e) { - log.error(e.getMessage()); + log.error(e.getMessage(), e); return HttpResponse.status(HttpStatus.NOT_FOUND, e.getMessage()); } }