From c2761149b233e890315f7b9c3b4f4cfdcd88fcc3 Mon Sep 17 00:00:00 2001 From: HMS17 Date: Thu, 15 Aug 2024 13:05:30 -0400 Subject: [PATCH 01/30] [BI-2256] - Experimental Collaborator BI-API Changes --- .../v1/controller/ExperimentController.java | 122 +++++++++++++++++- 1 file changed, 121 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java b/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java index 77214c9cf..01158e763 100644 --- a/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java +++ b/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java @@ -10,16 +10,20 @@ import io.micronaut.security.rules.SecurityRule; import lombok.extern.slf4j.Slf4j; import org.brapi.client.v2.model.exceptions.ApiException; +import org.breedinginsight.api.auth.AuthenticatedUser; import org.breedinginsight.api.auth.ProgramSecured; +import org.breedinginsight.api.auth.ProgramSecuredRole; import org.breedinginsight.api.auth.ProgramSecuredRoleGroup; import org.breedinginsight.api.model.v1.request.SubEntityDatasetRequest; import org.breedinginsight.api.model.v1.response.Response; import org.breedinginsight.brapi.v2.model.request.query.ExperimentExportQuery; import org.breedinginsight.brapi.v2.services.BrAPITrialService; +import org.breedinginsight.dao.db.tables.pojos.ExperimentProgramUserRoleEntity; import org.breedinginsight.model.Dataset; import org.breedinginsight.model.DatasetMetadata; import org.breedinginsight.model.DownloadFile; import org.breedinginsight.model.Program; +import org.breedinginsight.services.ExperimentalCollaboratorService; import org.breedinginsight.services.ProgramService; import org.breedinginsight.services.exceptions.DoesNotExistException; import org.breedinginsight.services.exceptions.UnprocessableEntityException; @@ -38,12 +42,14 @@ public class ExperimentController { private final BrAPITrialService experimentService; private final ExperimentQueryMapper experimentQueryMapper; private final ProgramService programService; + private final ExperimentalCollaboratorService experimentalCollaboratorService; @Inject - public ExperimentController(BrAPITrialService experimentService, ExperimentQueryMapper experimentQueryMapper, ProgramService programService) { + public ExperimentController(BrAPITrialService experimentService, ExperimentQueryMapper experimentQueryMapper, ProgramService programService, ExperimentalCollaboratorService experimentalCollaboratorService) { this.experimentService = experimentService; this.experimentQueryMapper = experimentQueryMapper; this.programService = programService; + this.experimentalCollaboratorService = experimentalCollaboratorService; } @Get("/${micronaut.bi.api.version}/programs/{programId}/experiments/{experimentId}/export{?queryParams*}") @@ -147,4 +153,118 @@ public HttpResponse>> getDatasets( return HttpResponse.ok(response); } + + /** + * Adds a record to the experiment_program_user_role table + * @param programId + * @param experimentId + * @param userId the UUID of the experimental collaborator + */ + @Post("/${micronaut.bi.api.version}/programs/{programId}/experiments/{experimentId}/collaborators") + @ProgramSecured(roles = {ProgramSecuredRole.PROGRAM_ADMIN, ProgramSecuredRole.SYSTEM_ADMIN}) + @Produces(MediaType.APPLICATION_JSON) + public HttpResponse> createExperimentalCollaborator( + @PathVariable("programId") UUID programId, + @PathVariable("experimentId") UUID experimentId, + @Body @Valid UUID userId + ) { + try { + Optional programOptional = programService.getById(programId); + if (programOptional.isEmpty()) { + return HttpResponse.status(HttpStatus.NOT_FOUND, "Program does not exist"); + } + //todo clarify body + //userId for downstream method the user creating + //programUserRoleId the experimental collaborator + + //AuthenticatedUser actingUser = securityService.getUser(); + + UUID programUserRoleId = userId; + + Response response = new Response(experimentalCollaboratorService.createExperimentalCollaborator(programUserRoleId,experimentId,userId)); + return HttpResponse.ok(response); + } catch (Exception e){ + log.info(e.getMessage()); + return HttpResponse.status(HttpStatus.UNPROCESSABLE_ENTITY, e.getMessage()); + } + + } + + /** + * Returns an array of collaborators for given experiment filterable using the active query parameter + * @param programId + * @param experimentId + * @param active + */ + @Get("/${micronaut.bi.api.version}/programs/{programId}/experiments/{experimentId}/collaborators?active=true/false") + @ProgramSecured(roles = {ProgramSecuredRole.PROGRAM_ADMIN, ProgramSecuredRole.SYSTEM_ADMIN}) + @Produces(MediaType.APPLICATION_JSON) + public HttpResponse>> getExperimentalCollaborators( + @PathVariable("programId") UUID programId, + @PathVariable("experimentId") UUID experimentId, + @QueryValue(defaultValue = "true") Boolean active + ) { + //todo confirm what default of active should be/if there should be a default + + try { + Program program = programService.getById(programId).orElseThrow(() -> new DoesNotExistException("Program does not exist")); + Response> response = new Response(experimentalCollaboratorService.getExperimentalCollaborators(experimentId)); + //todo filter by program and active + return HttpResponse.ok(response); + } catch (Exception e) { + log.info(e.getMessage(), e); + HttpResponse response = HttpResponse.status(HttpStatus.INTERNAL_SERVER_ERROR, "todo").contentType(MediaType.TEXT_PLAIN).body("todo"); + return response; + } + /* + active = true: program users with the Experimental Collaborator role who have been added as a collaborator to this experiment + + active = false: program users with the Experimental Collaborator role who have not been added as a collaborator to this experiment + + Includes name and email as a convenience to the front end to avoid making another api call + +Response: +[ + { + "id": UUID, + "active": Boolean, + "userId": UUID, + "name": String, + "email": String + }, + { + "id": UUID, + "active": Boolean, + "userId": UUID, + "name": String, + "email": String + } +] + */ + + } + + /** + * Removes record from experiment_program_user_role table + * @param programId + * @param experimentId + * @param collaboratorId + */ + @Delete("/${micronaut.bi.api.version}/programs/{programId}/experiments/{experimentId}/collaborators/{collaboratorId}") + @ProgramSecured(roles = {ProgramSecuredRole.PROGRAM_ADMIN, ProgramSecuredRole.SYSTEM_ADMIN}) + @Produces(MediaType.APPLICATION_JSON) + public HttpResponse deleteExperimentalCollaborator( + @PathVariable("programId") UUID programId, + @PathVariable("experimentId") UUID experimentId, + @PathVariable("collaboratorId") UUID collaboratorId + ) { + try { + experimentalCollaboratorService.deleteExperimentalCollaborator(collaboratorId); + return HttpResponse.ok(); + } catch (Exception e) { + log.error("Error deleting experimental collaborator.\n\tprogramId: " + programId + "\n\texperimentId: " + experimentId + "\n\tcollaboratorId: " + collaboratorId); + throw e; + } + + } } From 5a15024a9333b4220f00c6d658dedfd7da49495c Mon Sep 17 00:00:00 2001 From: Nick <53413353+nickpalladino@users.noreply.github.com> Date: Thu, 15 Aug 2024 17:02:33 -0400 Subject: [PATCH 02/30] Added first GET collaborators test and updated controller method --- .../v1/controller/ExperimentController.java | 26 +++++-- .../ExperimentControllerIntegrationTest.java | 67 +++++++++++++++++++ 2 files changed, 86 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java b/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java index 01158e763..1713e2386 100644 --- a/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java +++ b/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java @@ -15,14 +15,16 @@ import org.breedinginsight.api.auth.ProgramSecuredRole; import org.breedinginsight.api.auth.ProgramSecuredRoleGroup; import org.breedinginsight.api.model.v1.request.SubEntityDatasetRequest; +import org.breedinginsight.api.model.v1.response.DataResponse; import org.breedinginsight.api.model.v1.response.Response; +import org.breedinginsight.api.model.v1.response.metadata.Metadata; +import org.breedinginsight.api.model.v1.response.metadata.Pagination; +import org.breedinginsight.api.model.v1.response.metadata.Status; +import org.breedinginsight.api.model.v1.response.metadata.StatusCode; import org.breedinginsight.brapi.v2.model.request.query.ExperimentExportQuery; import org.breedinginsight.brapi.v2.services.BrAPITrialService; import org.breedinginsight.dao.db.tables.pojos.ExperimentProgramUserRoleEntity; -import org.breedinginsight.model.Dataset; -import org.breedinginsight.model.DatasetMetadata; -import org.breedinginsight.model.DownloadFile; -import org.breedinginsight.model.Program; +import org.breedinginsight.model.*; import org.breedinginsight.services.ExperimentalCollaboratorService; import org.breedinginsight.services.ProgramService; import org.breedinginsight.services.exceptions.DoesNotExistException; @@ -31,6 +33,7 @@ import javax.inject.Inject; import javax.validation.Valid; +import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.UUID; @@ -196,10 +199,10 @@ public HttpResponse> createExperimenta * @param experimentId * @param active */ - @Get("/${micronaut.bi.api.version}/programs/{programId}/experiments/{experimentId}/collaborators?active=true/false") + @Get("/${micronaut.bi.api.version}/programs/{programId}/experiments/{experimentId}/collaborators{?active}") @ProgramSecured(roles = {ProgramSecuredRole.PROGRAM_ADMIN, ProgramSecuredRole.SYSTEM_ADMIN}) @Produces(MediaType.APPLICATION_JSON) - public HttpResponse>> getExperimentalCollaborators( + public HttpResponse>> getExperimentalCollaborators( @PathVariable("programId") UUID programId, @PathVariable("experimentId") UUID experimentId, @QueryValue(defaultValue = "true") Boolean active @@ -208,8 +211,17 @@ public HttpResponse>> getExperime try { Program program = programService.getById(programId).orElseThrow(() -> new DoesNotExistException("Program does not exist")); - Response> response = new Response(experimentalCollaboratorService.getExperimentalCollaborators(experimentId)); + List collaborators = experimentalCollaboratorService.getExperimentalCollaborators(experimentId); + //Response> response = new Response(experimentalCollaboratorService.getExperimentalCollaborators(experimentId)); //todo filter by program and active + + List metadataStatus = new ArrayList<>(); + metadataStatus.add(new Status(StatusCode.INFO, "Successful Query")); + //TODO: paging + Pagination pagination = new Pagination(collaborators.size(), collaborators.size(), 1, 0); + Metadata metadata = new Metadata(pagination, metadataStatus); + + Response> response = new Response(metadata, new DataResponse<>(collaborators)); return HttpResponse.ok(response); } catch (Exception e) { log.info(e.getMessage(), e); diff --git a/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java b/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java index 7931ff587..c687d83c8 100644 --- a/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java +++ b/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java @@ -43,6 +43,7 @@ import org.junit.jupiter.api.*; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.ValueSource; import tech.tablesaw.api.ColumnType; import tech.tablesaw.api.Row; import tech.tablesaw.api.Table; @@ -52,6 +53,7 @@ import java.util.*; import java.util.stream.Collectors; import static io.micronaut.http.HttpRequest.*; +import static org.junit.Assert.assertNotEquals; import static org.junit.jupiter.api.Assertions.*; @MicronautTest @@ -348,6 +350,71 @@ void downloadSubEntityDataset(String extension) { parseAndCheck(plantBodyStream, extension, false, plantRows, false, 23); } + /** + * Tests for Experimental Collaborator endpoints + * + * Create Experimental Collaborator + * + * Remove Experimental Collaborator + * + * Get Experimental Collaborators None + * GIVEN GET /v1/programs/{programId}/experiments/{experimentId}/collaborators?active=true|false + * WHEN no users have been added as experiment collaborators + * AND no program users with Experimental Collaborator role exist in program + * THEN response should be an empty array regardless of active query parameter value + * + * Get Experimental Collaborators No Active + * GIVEN GET /v1/programs/{programId}/experiments/{experimentId}/collaborators?active=true|false + * WHEN no users have been added as experiment collaborators + * AND one or more program users with Experimental Collaborator role exist in program + * THEN response should be: + * empty array when active=true + * array with program user when active=false + * + * Get Experimental Collaborators Active + * GIVEN GET /v1/programs/{programId}/experiments/{experimentId}/collaborators?active=true|false + * WHEN program user has been added to experiment as collaborator + * AND program user with Experimental Collaborator role exists in program + * THEN response should be: + * array with program user when active=true + * empty array when active=false + * + * Get Experimental Collaborators Deactivated from Program + * GIVEN GET /v1/programs/{programId}/experiments/{experimentId}/collaborators?active=true|false + * WHEN program user has been added to experiment as collaborator + * AND after being added as a collaborator, program user is deactivated from program + * THEN response should be empty array regardless of active query parameter value (assumes single user) + * + */ + + /** + * Get Experimental Collaborators None + * GIVEN GET /v1/programs/{programId}/experiments/{experimentId}/collaborators?active=true|false + * WHEN no users have been added as experiment collaborators + * AND no program users with Experimental Collaborator role exist in program + * THEN response should be an empty array regardless of active query parameter value + * + * test-registered-user has Program Administration role in program + */ + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void getExperimentalCollaboratorsNone(boolean active) { + + Flowable> call = client.exchange( + GET(String.format("/programs/%s/experiments/%s/collaborators?active=%s", program.getId().toString(), experimentId, active)) + .contentType(MediaType.APPLICATION_JSON) + .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(0, data.size()); + } + + private List> buildSubEntityRows(List> topLevelRows, String entityName, int repeatedMeasures) { List> plantRows = new ArrayList<>(); for (Map row : topLevelRows) { From 2a9b748117453bac0f8fc6a83a1e6ba167907f08 Mon Sep 17 00:00:00 2001 From: HMS17 Date: Fri, 16 Aug 2024 16:12:14 -0400 Subject: [PATCH 03/30] [BI-2256] - Small refactoring, endpoint progress --- .../v1/controller/ExperimentController.java | 75 +++++++++++-------- .../daos/ExperimentalCollaboratorDAO.java | 6 +- .../ExperimentalCollaboratorService.java | 6 +- 3 files changed, 50 insertions(+), 37 deletions(-) diff --git a/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java b/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java index 1713e2386..cf37689b2 100644 --- a/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java +++ b/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java @@ -10,10 +10,7 @@ import io.micronaut.security.rules.SecurityRule; import lombok.extern.slf4j.Slf4j; import org.brapi.client.v2.model.exceptions.ApiException; -import org.breedinginsight.api.auth.AuthenticatedUser; -import org.breedinginsight.api.auth.ProgramSecured; -import org.breedinginsight.api.auth.ProgramSecuredRole; -import org.breedinginsight.api.auth.ProgramSecuredRoleGroup; +import org.breedinginsight.api.auth.*; import org.breedinginsight.api.model.v1.request.SubEntityDatasetRequest; import org.breedinginsight.api.model.v1.response.DataResponse; import org.breedinginsight.api.model.v1.response.Response; @@ -46,13 +43,15 @@ public class ExperimentController { private final ExperimentQueryMapper experimentQueryMapper; private final ProgramService programService; private final ExperimentalCollaboratorService experimentalCollaboratorService; + private final SecurityService securityService; @Inject - public ExperimentController(BrAPITrialService experimentService, ExperimentQueryMapper experimentQueryMapper, ProgramService programService, ExperimentalCollaboratorService experimentalCollaboratorService) { + public ExperimentController(BrAPITrialService experimentService, ExperimentQueryMapper experimentQueryMapper, ProgramService programService, ExperimentalCollaboratorService experimentalCollaboratorService, SecurityService securityService) { this.experimentService = experimentService; this.experimentQueryMapper = experimentQueryMapper; this.programService = programService; this.experimentalCollaboratorService = experimentalCollaboratorService; + this.securityService = securityService; } @Get("/${micronaut.bi.api.version}/programs/{programId}/experiments/{experimentId}/export{?queryParams*}") @@ -138,7 +137,7 @@ public HttpResponse> createSubEntityDataset( * @param experimentId The UUID of the experiment. * @return An HttpResponse with a Response object containing a list of DatasetMetadata. * @throws DoesNotExistException if the program does not exist. - * @throws ApiException if an error occurs while retrieving the datasets. + * @throws ApiException if an error occurs while retrieving the datasets.UserId */ @Get("/${micronaut.bi.api.version}/programs/{programId}/experiments/{experimentId}/datasets") @ProgramSecured(roleGroups = {ProgramSecuredRoleGroup.ALL}) @@ -159,9 +158,10 @@ public HttpResponse>> getDatasets( /** * Adds a record to the experiment_program_user_role table - * @param programId - * @param experimentId - * @param userId the UUID of the experimental collaborator + * @param programId The UUID of the program + * @param experimentId The UUID of the experiment + * @param programUserRoleId The UUID of the program user + * @return HttpResponse containing the newly created ExperimentProgramUserRoleEntity */ @Post("/${micronaut.bi.api.version}/programs/{programId}/experiments/{experimentId}/collaborators") @ProgramSecured(roles = {ProgramSecuredRole.PROGRAM_ADMIN, ProgramSecuredRole.SYSTEM_ADMIN}) @@ -169,22 +169,19 @@ public HttpResponse>> getDatasets( public HttpResponse> createExperimentalCollaborator( @PathVariable("programId") UUID programId, @PathVariable("experimentId") UUID experimentId, - @Body @Valid UUID userId + @Body @Valid UUID programUserRoleId ) { try { Optional programOptional = programService.getById(programId); if (programOptional.isEmpty()) { return HttpResponse.status(HttpStatus.NOT_FOUND, "Program does not exist"); } - //todo clarify body - //userId for downstream method the user creating - //programUserRoleId the experimental collaborator - //AuthenticatedUser actingUser = securityService.getUser(); + //get active user creating the collaborator + AuthenticatedUser createdByUser = securityService.getUser(); + UUID createdByUserId = createdByUser.getId(); - UUID programUserRoleId = userId; - - Response response = new Response(experimentalCollaboratorService.createExperimentalCollaborator(programUserRoleId,experimentId,userId)); + Response response = new Response(experimentalCollaboratorService.createExperimentalCollaborator(programUserRoleId,experimentId,createdByUserId)); return HttpResponse.ok(response); } catch (Exception e){ log.info(e.getMessage()); @@ -195,9 +192,11 @@ public HttpResponse> createExperimenta /** * Returns an array of collaborators for given experiment filterable using the active query parameter - * @param programId - * @param experimentId - * @param active + * @param programId The UUID of the program + * @param experimentId The UUID of the experiment + * @param active true if querying for collaborators added as a collaborator to the experiment, false if querying for collaborators not added + * @return + * Response includes name and email as a convenience to the front end to avoid making another api call */ @Get("/${micronaut.bi.api.version}/programs/{programId}/experiments/{experimentId}/collaborators{?active}") @ProgramSecured(roles = {ProgramSecuredRole.PROGRAM_ADMIN, ProgramSecuredRole.SYSTEM_ADMIN}) @@ -211,9 +210,26 @@ public HttpResponse>> get try { Program program = programService.getById(programId).orElseThrow(() -> new DoesNotExistException("Program does not exist")); + + //Get experimental collaborators associated with the experiment List collaborators = experimentalCollaboratorService.getExperimentalCollaborators(experimentId); + + //Get all program users with experimental collaborator role + //List collabRoleUsers = programService. + + if (active){ + //return users with experimental collaborator role associated with this experiment + } else { + //return users with experimental collaborator role NOT associated with this experiment + } + + //may end up needing helper method + + //Response> response = new Response(experimentalCollaboratorService.getExperimentalCollaborators(experimentId)); - //todo filter by program and active + + //programuserservice, programusers with expcollab role and then could collaborators on experiment + List metadataStatus = new ArrayList<>(); metadataStatus.add(new Status(StatusCode.INFO, "Successful Query")); @@ -229,18 +245,13 @@ public HttpResponse>> get return response; } /* - active = true: program users with the Experimental Collaborator role who have been added as a collaborator to this experiment - - active = false: program users with the Experimental Collaborator role who have not been added as a collaborator to this experiment - - Includes name and email as a convenience to the front end to avoid making another api call Response: [ { - "id": UUID, + "id": UUID, collaboratorId "active": Boolean, - "userId": UUID, + "userId": UUID,programUserId "name": String, "email": String }, @@ -258,9 +269,10 @@ public HttpResponse>> get /** * Removes record from experiment_program_user_role table - * @param programId - * @param experimentId - * @param collaboratorId + * @param programId The UUID of the program + * @param experimentId The UUID of the experiment + * @param collaboratorId The UUID of the collaborator, referring to a unique experiment-program user role combo in the experiment_program_user_role table + * @return A Http Response */ @Delete("/${micronaut.bi.api.version}/programs/{programId}/experiments/{experimentId}/collaborators/{collaboratorId}") @ProgramSecured(roles = {ProgramSecuredRole.PROGRAM_ADMIN, ProgramSecuredRole.SYSTEM_ADMIN}) @@ -271,6 +283,7 @@ public HttpResponse deleteExperimentalCollaborator( @PathVariable("collaboratorId") UUID collaboratorId ) { try { + //todo double check this endpoint would be getting the collaboratorId and not the programUserRoleId experimentalCollaboratorService.deleteExperimentalCollaborator(collaboratorId); return HttpResponse.ok(); } catch (Exception e) { diff --git a/src/main/java/org/breedinginsight/daos/ExperimentalCollaboratorDAO.java b/src/main/java/org/breedinginsight/daos/ExperimentalCollaboratorDAO.java index 0187c55b5..ccf3741ee 100644 --- a/src/main/java/org/breedinginsight/daos/ExperimentalCollaboratorDAO.java +++ b/src/main/java/org/breedinginsight/daos/ExperimentalCollaboratorDAO.java @@ -43,7 +43,7 @@ public ExperimentalCollaboratorDAO(Configuration config, DSLContext dsl) { this.dsl = dsl; } - public ExperimentProgramUserRoleEntity create(UUID experimentId, UUID programUserRoleId, UUID userId) { + public ExperimentProgramUserRoleEntity create(UUID experimentId, UUID programUserRoleId, UUID createdByUserId) { return dsl.insertInto(EXPERIMENT_PROGRAM_USER_ROLE) .columns(EXPERIMENT_PROGRAM_USER_ROLE.EXPERIMENT_ID, EXPERIMENT_PROGRAM_USER_ROLE.PROGRAM_USER_ROLE_ID, @@ -53,9 +53,9 @@ public ExperimentProgramUserRoleEntity create(UUID experimentId, UUID programUse EXPERIMENT_PROGRAM_USER_ROLE.UPDATED_AT) .values(experimentId, programUserRoleId, - userId, + createdByUserId, OffsetDateTime.now(), - userId, + createdByUserId, OffsetDateTime.now()) .returning(EXPERIMENT_PROGRAM_USER_ROLE.fields()) .fetchOneInto(ExperimentProgramUserRoleEntity.class); diff --git a/src/main/java/org/breedinginsight/services/ExperimentalCollaboratorService.java b/src/main/java/org/breedinginsight/services/ExperimentalCollaboratorService.java index f6fe07390..f0349c9e9 100644 --- a/src/main/java/org/breedinginsight/services/ExperimentalCollaboratorService.java +++ b/src/main/java/org/breedinginsight/services/ExperimentalCollaboratorService.java @@ -37,8 +37,8 @@ public ExperimentalCollaboratorService(ExperimentalCollaboratorDAO experimentalC this.experimentalCollaboratorDAO = experimentalCollaboratorDAO; } - public ExperimentProgramUserRoleEntity createExperimentalCollaborator(UUID programUserRoleId, UUID experimentId, UUID userId) { - return this.experimentalCollaboratorDAO.create(experimentId, programUserRoleId, userId); + public ExperimentProgramUserRoleEntity createExperimentalCollaborator(UUID programUserRoleId, UUID experimentId, UUID createdByUserId) { + return this.experimentalCollaboratorDAO.create(experimentId, programUserRoleId, createdByUserId); } public List getExperimentalCollaborators(UUID experimentId) { @@ -47,7 +47,7 @@ public List getExperimentalCollaborators(UUID e } public void deleteExperimentalCollaborator(UUID collaboratorId) { - // Note: collaboratorId is the PK of the experiment_program_user_role table. + // Note: collaboratorId is the primary key of the experiment_program_user_role table. this.experimentalCollaboratorDAO.deleteById(collaboratorId); } } From 4b5f9b40aeca9759668eacb7e7a279133d1b4a8f Mon Sep 17 00:00:00 2001 From: HMS17 Date: Fri, 16 Aug 2024 18:08:59 -0400 Subject: [PATCH 04/30] [BI-2256] - Working on GET, RoleService helper method --- .../v1/controller/ExperimentController.java | 43 +++++++++++++------ .../breedinginsight/services/RoleService.java | 12 ++++++ 2 files changed, 43 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java b/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java index cf37689b2..cb21ae20d 100644 --- a/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java +++ b/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java @@ -24,6 +24,8 @@ import org.breedinginsight.model.*; import org.breedinginsight.services.ExperimentalCollaboratorService; import org.breedinginsight.services.ProgramService; +import org.breedinginsight.services.ProgramUserService; +import org.breedinginsight.services.RoleService; import org.breedinginsight.services.exceptions.DoesNotExistException; import org.breedinginsight.services.exceptions.UnprocessableEntityException; import org.breedinginsight.utilities.response.mappers.ExperimentQueryMapper; @@ -44,14 +46,18 @@ public class ExperimentController { private final ProgramService programService; private final ExperimentalCollaboratorService experimentalCollaboratorService; private final SecurityService securityService; + private final ProgramUserService programUserService; + private final RoleService roleService; @Inject - public ExperimentController(BrAPITrialService experimentService, ExperimentQueryMapper experimentQueryMapper, ProgramService programService, ExperimentalCollaboratorService experimentalCollaboratorService, SecurityService securityService) { + public ExperimentController(BrAPITrialService experimentService, ExperimentQueryMapper experimentQueryMapper, ProgramService programService, ExperimentalCollaboratorService experimentalCollaboratorService, SecurityService securityService, ProgramUserService programUserService, RoleService roleService) { this.experimentService = experimentService; this.experimentQueryMapper = experimentQueryMapper; this.programService = programService; this.experimentalCollaboratorService = experimentalCollaboratorService; this.securityService = securityService; + this.programUserService = programUserService; + this.roleService = roleService; } @Get("/${micronaut.bi.api.version}/programs/{programId}/experiments/{experimentId}/export{?queryParams*}") @@ -209,27 +215,40 @@ public HttpResponse>> get //todo confirm what default of active should be/if there should be a default try { - Program program = programService.getById(programId).orElseThrow(() -> new DoesNotExistException("Program does not exist")); + //Program program = programService.getById(programId).orElseThrow(() -> new DoesNotExistException("Program does not exist")); //Get experimental collaborators associated with the experiment List collaborators = experimentalCollaboratorService.getExperimentalCollaborators(experimentId); - //Get all program users with experimental collaborator role - //List collabRoleUsers = programService. + //Get roleId for experimental collaborator role + Role experimentalCollabRole = roleService.getRoleByDomain(ProgramSecuredRole.EXPERIMENTAL_COLLABORATOR.toString()).get(); + UUID roleId = experimentalCollabRole.getId(); - if (active){ - //return users with experimental collaborator role associated with this experiment - } else { - //return users with experimental collaborator role NOT associated with this experiment + //Get all program users with experimental collaborator role + List collabRoleUsers = programUserService.getProgramUsersByRole(programId, roleId); + + //let's start with case of finding users not assoc with experiment + //need new fancy model maybe + + Boolean isACollaborator = false; + for (ProgramUser collabRoleUser : collabRoleUsers) { + //if collabRoleUser.getUser().getId(); + //should be something more efficient, right? + if (active){ + //return users with experimental collaborator role associated with this experiment + } else { + //return users with experimental collaborator role NOT associated with this experiment + } } - //may end up needing helper method - + //wait what *is* response type + //model ExperimentalCollaboratorResponse - //Response> response = new Response(experimentalCollaboratorService.getExperimentalCollaborators(experimentId)); - //programuserservice, programusers with expcollab role and then could collaborators on experiment + //biuser has name and email + //program_user_role has id, user_id + //experimentProgramUserRoleEntity with some stuff appended on List metadataStatus = new ArrayList<>(); metadataStatus.add(new Status(StatusCode.INFO, "Successful Query")); diff --git a/src/main/java/org/breedinginsight/services/RoleService.java b/src/main/java/org/breedinginsight/services/RoleService.java index ecc9fc4e5..63165fdf0 100644 --- a/src/main/java/org/breedinginsight/services/RoleService.java +++ b/src/main/java/org/breedinginsight/services/RoleService.java @@ -17,6 +17,9 @@ package org.breedinginsight.services; +import io.micronaut.http.HttpResponse; +import io.micronaut.http.HttpStatus; +import io.micronaut.http.MediaType; import lombok.extern.slf4j.Slf4j; import org.breedinginsight.dao.db.tables.daos.RoleDao; import org.breedinginsight.dao.db.tables.pojos.RoleEntity; @@ -66,4 +69,13 @@ public List getRolesByIds(List roleIds) { return roles; } + public Optional getRoleByDomain(String domain) { + RoleEntity role = dao.fetchByDomain(domain).get(0); + if (role == null) { + return Optional.empty(); + } + + return Optional.of(new Role(role)); + } + } From c8763fe8eb28e96b038f6d4b0616362227e9c787 Mon Sep 17 00:00:00 2001 From: Nick <53413353+nickpalladino@users.noreply.github.com> Date: Mon, 19 Aug 2024 10:17:57 -0400 Subject: [PATCH 05/30] Added second GET test and some user setup and teardown --- .../org/breedinginsight/utilities/out.csv | 8 +++ .../ExperimentControllerIntegrationTest.java | 49 ++++++++++++++++++- ...amSecuredAnnotationRuleIntegrationTest.sql | 22 +++++++++ 3 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/breedinginsight/utilities/out.csv diff --git a/src/main/java/org/breedinginsight/utilities/out.csv b/src/main/java/org/breedinginsight/utilities/out.csv new file mode 100644 index 000000000..d5f869930 --- /dev/null +++ b/src/main/java/org/breedinginsight/utilities/out.csv @@ -0,0 +1,8 @@ +genotype,genotype_uncertainty,plot,plot_uncertainty,height,height_uncertainty,rating,rating_uncertainty,notes,notes_uncertainty +Apple,FALSE,1001,FALSE,7,FALSE,1,FALSE,Bad germ,FALSE +Xnana,FALSE,1002,FALSE,8.2,TRUE,2,FALSE,,TRUE +Clementine,FALSE,1003,FALSE,128,TRUE,1,FALSE,missing,FALSE +Durian,FALSE,1004,FALSE,8,TRUE,3,FALSE,,TRUE +Elephant,FALSE,1005,FALSE,6.38,FALSE,4,FALSE,missing,FALSE +Framboise,FALSE,1006,FALSE,10,FALSE,5,FALSE,,TRUE +Grapes,FALSE,1007,FALSE,3,FALSE,6,FALSE,NA,FALSE \ No newline at end of file diff --git a/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java b/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java index c687d83c8..25f122af0 100644 --- a/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java +++ b/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java @@ -40,6 +40,7 @@ import org.breedinginsight.utilities.DatasetUtil; import org.breedinginsight.utilities.FileUtil; import org.jooq.DSLContext; +import org.junit.Test; import org.junit.jupiter.api.*; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; @@ -67,6 +68,8 @@ public class ExperimentControllerIntegrationTest extends BrAPITest { private final List> rows = new ArrayList<>(); private final List columns = ExperimentFileColumns.getOrderedColumns(); private List traits; + private User testUser; + private User otherTestUser; @Property(name = "brapi.server.reference-source") private String BRAPI_REFERENCE_SOURCE; @@ -101,7 +104,9 @@ void setup() throws Exception { FannyPack brapiFp = FannyPack.fill("src/test/resources/sql/brapi/species.sql"); // Test User - User testUser = userDAO.getUserByOrcId(TestTokenValidator.TEST_USER_ORCID).orElseThrow(Exception::new); + testUser = userDAO.getUserByOrcId(TestTokenValidator.TEST_USER_ORCID).orElseThrow(Exception::new); + otherTestUser = userDAO.getUserByOrcId(TestTokenValidator.OTHER_TEST_USER_ORCID).orElseThrow(Exception::new); + dsl.execute(securityFp.get("InsertSystemRoleAdmin"), testUser.getId().toString()); // Species @@ -414,6 +419,48 @@ public void getExperimentalCollaboratorsNone(boolean active) { assertEquals(0, data.size()); } + /** + * Get Experimental Collaborators No Active + * GIVEN GET /v1/programs/{programId}/experiments/{experimentId}/collaborators?active=true|false + * WHEN no users have been added as experiment collaborators + * AND one or more program users with Experimental Collaborator role exist in program + * THEN response should be: + * empty array when active=true + * array with program user when active=false + */ + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void getExperimentalCollaboratorsNoActive(boolean active) { + + // add a program user with the experimental collaborator role + FannyPack securityFp = FannyPack.fill("src/test/resources/sql/ProgramSecuredAnnotationRuleIntegrationTest.sql"); + dsl.execute(securityFp.get("InsertProgramRolesExperimentalCollaborator"), otherTestUser.getId().toString(), program.getId()); + + Flowable> call = client.exchange( + GET(String.format("/programs/%s/experiments/%s/collaborators?active=%s", program.getId().toString(), experimentId, active)) + .contentType(MediaType.APPLICATION_JSON) + .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"); + + if (active) { + assertEquals(0, data.size()); + } else { + assertEquals(1, data.size()); + // TODO: check user details + + } + + // delete program user from setup + // NOTE: if test fails this may not be run and could impact other tests results + dsl.execute(securityFp.get("DeleteProgramUser"), otherTestUser.getId().toString()); + + } private List> buildSubEntityRows(List> topLevelRows, String entityName, int repeatedMeasures) { List> plantRows = new ArrayList<>(); diff --git a/src/test/resources/sql/ProgramSecuredAnnotationRuleIntegrationTest.sql b/src/test/resources/sql/ProgramSecuredAnnotationRuleIntegrationTest.sql index 17f08c19d..dc4e40e49 100644 --- a/src/test/resources/sql/ProgramSecuredAnnotationRuleIntegrationTest.sql +++ b/src/test/resources/sql/ProgramSecuredAnnotationRuleIntegrationTest.sql @@ -53,6 +53,28 @@ bi_user join role on role.domain = 'Program Administrator' where bi_user.name = 'system'; +-- name: InsertProgramRolesExperimentalCollaborator + +insert into program_user_role (user_id, program_id, role_id, created_by, updated_by) +select + ?::uuid, ?::uuid, role.id, bi_user.id, bi_user.id +from + bi_user + join role on role.domain = 'Experimental Collaborator' +where bi_user.name = 'system'; + +-- name: DeleteExperimentalCollaboratorProgramUsers + +DELETE FROM program_user_role + USING role +WHERE program_user_role.role_id = role.id + AND role.domain = 'Experimental Collaborator'; + +-- name: DeleteProgramUser + +DELETE FROM program_user_role +WHERE user_id = :id::uuid; + -- name: InsertSystemRoleAdmin insert into system_user_role (bi_user_id, system_role_id, created_by, updated_by) From 6f24db7bc38be82f21a000d7c771bf0abf344ea1 Mon Sep 17 00:00:00 2001 From: Nick <53413353+nickpalladino@users.noreply.github.com> Date: Mon, 19 Aug 2024 10:19:58 -0400 Subject: [PATCH 06/30] Delete src/main/java/org/breedinginsight/utilities/out.csv --- src/main/java/org/breedinginsight/utilities/out.csv | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 src/main/java/org/breedinginsight/utilities/out.csv diff --git a/src/main/java/org/breedinginsight/utilities/out.csv b/src/main/java/org/breedinginsight/utilities/out.csv deleted file mode 100644 index d5f869930..000000000 --- a/src/main/java/org/breedinginsight/utilities/out.csv +++ /dev/null @@ -1,8 +0,0 @@ -genotype,genotype_uncertainty,plot,plot_uncertainty,height,height_uncertainty,rating,rating_uncertainty,notes,notes_uncertainty -Apple,FALSE,1001,FALSE,7,FALSE,1,FALSE,Bad germ,FALSE -Xnana,FALSE,1002,FALSE,8.2,TRUE,2,FALSE,,TRUE -Clementine,FALSE,1003,FALSE,128,TRUE,1,FALSE,missing,FALSE -Durian,FALSE,1004,FALSE,8,TRUE,3,FALSE,,TRUE -Elephant,FALSE,1005,FALSE,6.38,FALSE,4,FALSE,missing,FALSE -Framboise,FALSE,1006,FALSE,10,FALSE,5,FALSE,,TRUE -Grapes,FALSE,1007,FALSE,3,FALSE,6,FALSE,NA,FALSE \ No newline at end of file From 65cbbdecbcfbb1143758f79c2817023a439e3b1e Mon Sep 17 00:00:00 2001 From: Nick <53413353+nickpalladino@users.noreply.github.com> Date: Mon, 19 Aug 2024 16:49:43 -0400 Subject: [PATCH 07/30] Added test for POST with invalid program user id and updated request body --- .../ExperimentCollaboratorRequest.java | 19 +++++++ .../v1/controller/ExperimentController.java | 9 ++-- .../ExperimentControllerIntegrationTest.java | 51 +++++++++++-------- 3 files changed, 55 insertions(+), 24 deletions(-) create mode 100644 src/main/java/org/breedinginsight/api/model/v1/request/ExperimentCollaboratorRequest.java diff --git a/src/main/java/org/breedinginsight/api/model/v1/request/ExperimentCollaboratorRequest.java b/src/main/java/org/breedinginsight/api/model/v1/request/ExperimentCollaboratorRequest.java new file mode 100644 index 000000000..85a1e43b9 --- /dev/null +++ b/src/main/java/org/breedinginsight/api/model/v1/request/ExperimentCollaboratorRequest.java @@ -0,0 +1,19 @@ +package org.breedinginsight.api.model.v1.request; + +import io.micronaut.core.annotation.Introspected; +import lombok.*; + +import javax.validation.constraints.NotBlank; +import java.util.UUID; + +@Getter +@Setter +@Builder +@ToString +@AllArgsConstructor +@NoArgsConstructor +@Introspected +public class ExperimentCollaboratorRequest { + @NotBlank + private UUID programUserId; +} diff --git a/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java b/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java index cb21ae20d..64e24c3ab 100644 --- a/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java +++ b/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java @@ -11,6 +11,7 @@ import lombok.extern.slf4j.Slf4j; import org.brapi.client.v2.model.exceptions.ApiException; import org.breedinginsight.api.auth.*; +import org.breedinginsight.api.model.v1.request.ExperimentCollaboratorRequest; import org.breedinginsight.api.model.v1.request.SubEntityDatasetRequest; import org.breedinginsight.api.model.v1.response.DataResponse; import org.breedinginsight.api.model.v1.response.Response; @@ -166,7 +167,7 @@ public HttpResponse>> getDatasets( * Adds a record to the experiment_program_user_role table * @param programId The UUID of the program * @param experimentId The UUID of the experiment - * @param programUserRoleId The UUID of the program user + * @param programUserId The UUID of the program user * @return HttpResponse containing the newly created ExperimentProgramUserRoleEntity */ @Post("/${micronaut.bi.api.version}/programs/{programId}/experiments/{experimentId}/collaborators") @@ -175,7 +176,7 @@ public HttpResponse>> getDatasets( public HttpResponse> createExperimentalCollaborator( @PathVariable("programId") UUID programId, @PathVariable("experimentId") UUID experimentId, - @Body @Valid UUID programUserRoleId + @Body @Valid ExperimentCollaboratorRequest request ) { try { Optional programOptional = programService.getById(programId); @@ -186,8 +187,8 @@ public HttpResponse> createExperimenta //get active user creating the collaborator AuthenticatedUser createdByUser = securityService.getUser(); UUID createdByUserId = createdByUser.getId(); - - Response response = new Response(experimentalCollaboratorService.createExperimentalCollaborator(programUserRoleId,experimentId,createdByUserId)); + UUID programUserId = request.getProgramUserId(); + Response response = new Response(experimentalCollaboratorService.createExperimentalCollaborator(programUserId,experimentId,createdByUserId)); return HttpResponse.ok(response); } catch (Exception e){ log.info(e.getMessage()); diff --git a/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java b/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java index 25f122af0..3d032b984 100644 --- a/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java +++ b/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java @@ -8,6 +8,7 @@ import io.micronaut.http.MediaType; import io.micronaut.http.client.RxHttpClient; import io.micronaut.http.client.annotation.Client; +import io.micronaut.http.client.exceptions.HttpClientResponseException; import io.micronaut.http.netty.cookies.NettyCookie; import io.micronaut.test.annotation.MicronautTest; import io.reactivex.Flowable; @@ -40,7 +41,6 @@ import org.breedinginsight.utilities.DatasetUtil; import org.breedinginsight.utilities.FileUtil; import org.jooq.DSLContext; -import org.junit.Test; import org.junit.jupiter.api.*; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; @@ -362,19 +362,6 @@ void downloadSubEntityDataset(String extension) { * * Remove Experimental Collaborator * - * Get Experimental Collaborators None - * GIVEN GET /v1/programs/{programId}/experiments/{experimentId}/collaborators?active=true|false - * WHEN no users have been added as experiment collaborators - * AND no program users with Experimental Collaborator role exist in program - * THEN response should be an empty array regardless of active query parameter value - * - * Get Experimental Collaborators No Active - * GIVEN GET /v1/programs/{programId}/experiments/{experimentId}/collaborators?active=true|false - * WHEN no users have been added as experiment collaborators - * AND one or more program users with Experimental Collaborator role exist in program - * THEN response should be: - * empty array when active=true - * array with program user when active=false * * Get Experimental Collaborators Active * GIVEN GET /v1/programs/{programId}/experiments/{experimentId}/collaborators?active=true|false @@ -393,13 +380,37 @@ void downloadSubEntityDataset(String extension) { */ /** - * Get Experimental Collaborators None - * GIVEN GET /v1/programs/{programId}/experiments/{experimentId}/collaborators?active=true|false - * WHEN no users have been added as experiment collaborators - * AND no program users with Experimental Collaborator role exist in program - * THEN response should be an empty array regardless of active query parameter value + * Create Experimental Collaborator Invalid Id + * GIVEN POST /v1/programs/{programId}/experiments/{experimentId}/collaborators + * WHEN an invalid id is passed in the body of the request + * THEN response should be 422 (maybe should be bad request?) + */ + @Test + public void postExperimentalCollaboratorsInvalidId() { + JsonObject requestBody = new JsonObject(); + requestBody.addProperty("programUserId", "f47ac10b-58cc-4372-a567-0e02b2c3d479"); + + Flowable> call = client.exchange( + POST(String.format("/programs/%s/experiments/%s/collaborators", program.getId().toString(), experimentId), requestBody.toString()) + .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()); + } + + /** + * Get Experimental Collaborators None + * GIVEN GET /v1/programs/{programId}/experiments/{experimentId}/collaborators?active=true|false + * WHEN no users have been added as experiment collaborators + * AND no program users with Experimental Collaborator role exist in program + * THEN response should be an empty array regardless of active query parameter value * - * test-registered-user has Program Administration role in program + * test-registered-user has Program Administration role in program */ @ParameterizedTest @ValueSource(booleans = {true, false}) From feb6258cc7a6d8d17b4bafcdffefed528f788f40 Mon Sep 17 00:00:00 2001 From: HMS17 Date: Tue, 20 Aug 2024 14:04:19 -0400 Subject: [PATCH 08/30] [BI-2256] - GET method, some other fixes --- .../ExperimentalCollaboratorResponse.java | 45 +++++++++++ .../v1/controller/ExperimentController.java | 74 ++++++++----------- 2 files changed, 76 insertions(+), 43 deletions(-) create mode 100644 src/main/java/org/breedinginsight/api/model/v1/response/ExperimentalCollaboratorResponse.java diff --git a/src/main/java/org/breedinginsight/api/model/v1/response/ExperimentalCollaboratorResponse.java b/src/main/java/org/breedinginsight/api/model/v1/response/ExperimentalCollaboratorResponse.java new file mode 100644 index 000000000..d9a308787 --- /dev/null +++ b/src/main/java/org/breedinginsight/api/model/v1/response/ExperimentalCollaboratorResponse.java @@ -0,0 +1,45 @@ +/* + * See the NOTICE file distributed with this work for additional information + * regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.breedinginsight.api.model.v1.response; + +import lombok.*; +import lombok.experimental.Accessors; + +import javax.validation.constraints.NotNull; +import java.util.UUID; + +@Getter +@Setter +@Accessors(chain=true) +@ToString +@NoArgsConstructor +@AllArgsConstructor +public class ExperimentalCollaboratorResponse { + //is null in case where active=false + private UUID collaboratorId; + @NotNull + private Boolean active; + @NotNull + private UUID programUserId; + @NotNull + private String name; + @NotNull + private String email; + //todo determine notblank vs notnull + +} diff --git a/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java b/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java index 64e24c3ab..2cee30aef 100644 --- a/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java +++ b/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java @@ -14,6 +14,7 @@ import org.breedinginsight.api.model.v1.request.ExperimentCollaboratorRequest; import org.breedinginsight.api.model.v1.request.SubEntityDatasetRequest; import org.breedinginsight.api.model.v1.response.DataResponse; +import org.breedinginsight.api.model.v1.response.ExperimentalCollaboratorResponse; import org.breedinginsight.api.model.v1.response.Response; import org.breedinginsight.api.model.v1.response.metadata.Metadata; import org.breedinginsight.api.model.v1.response.metadata.Pagination; @@ -29,6 +30,7 @@ import org.breedinginsight.services.RoleService; import org.breedinginsight.services.exceptions.DoesNotExistException; import org.breedinginsight.services.exceptions.UnprocessableEntityException; +import org.breedinginsight.utilities.Utilities; import org.breedinginsight.utilities.response.mappers.ExperimentQueryMapper; import javax.inject.Inject; @@ -37,6 +39,7 @@ import java.util.List; import java.util.Optional; import java.util.UUID; +import java.util.stream.Collectors; @Slf4j @Controller @@ -167,7 +170,7 @@ public HttpResponse>> getDatasets( * Adds a record to the experiment_program_user_role table * @param programId The UUID of the program * @param experimentId The UUID of the experiment - * @param programUserId The UUID of the program user + * @param request ExperimentalCollaboratorRequest containing the UUID of the program user to add as a collaborator to the experiemnt * @return HttpResponse containing the newly created ExperimentProgramUserRoleEntity */ @Post("/${micronaut.bi.api.version}/programs/{programId}/experiments/{experimentId}/collaborators") @@ -179,11 +182,18 @@ public HttpResponse> createExperimenta @Body @Valid ExperimentCollaboratorRequest request ) { try { + //Check if program exists Optional programOptional = programService.getById(programId); if (programOptional.isEmpty()) { return HttpResponse.status(HttpStatus.NOT_FOUND, "Program does not exist"); } + //Check if program user exists + Optional programUserOptional = programUserService.getProgramUserbyId(programId, request.getProgramUserId()); + if (programUserOptional.isEmpty()) { + return HttpResponse.status(HttpStatus.NOT_FOUND, "Program user does not exist"); + } + //get active user creating the collaborator AuthenticatedUser createdByUser = securityService.getUser(); UUID createdByUserId = createdByUser.getId(); @@ -208,7 +218,7 @@ public HttpResponse> createExperimenta @Get("/${micronaut.bi.api.version}/programs/{programId}/experiments/{experimentId}/collaborators{?active}") @ProgramSecured(roles = {ProgramSecuredRole.PROGRAM_ADMIN, ProgramSecuredRole.SYSTEM_ADMIN}) @Produces(MediaType.APPLICATION_JSON) - public HttpResponse>> getExperimentalCollaborators( + public HttpResponse>>> getExperimentalCollaborators( @PathVariable("programId") UUID programId, @PathVariable("experimentId") UUID experimentId, @QueryValue(defaultValue = "true") Boolean active @@ -220,6 +230,7 @@ public HttpResponse>> get //Get experimental collaborators associated with the experiment List collaborators = experimentalCollaboratorService.getExperimentalCollaborators(experimentId); + List activeCollaboratorIds = collaborators.stream().map((ExperimentProgramUserRoleEntity::getProgramUserRoleId)).collect(Collectors.toList()); //Get roleId for experimental collaborator role Role experimentalCollabRole = roleService.getRoleByDomain(ProgramSecuredRole.EXPERIMENTAL_COLLABORATOR.toString()).get(); @@ -227,63 +238,40 @@ public HttpResponse>> get //Get all program users with experimental collaborator role List collabRoleUsers = programUserService.getProgramUsersByRole(programId, roleId); + List collaboratorResponses = new ArrayList<>(); - //let's start with case of finding users not assoc with experiment - //need new fancy model maybe - - Boolean isACollaborator = false; for (ProgramUser collabRoleUser : collabRoleUsers) { - //if collabRoleUser.getUser().getId(); - //should be something more efficient, right? - if (active){ - //return users with experimental collaborator role associated with this experiment - } else { - //return users with experimental collaborator role NOT associated with this experiment + UUID collaboratorId = null; + //check if user is an active collaborator for this experiment + Boolean isThisExpCollab = activeCollaboratorIds.contains(collabRoleUser.getId()); + + //If active, want to retrieve experimental collaborators added to the experiment + //If not active, want to retrieve experimental collaborators not added to the experiment + if ((active && isThisExpCollab) || (!active && !isThisExpCollab)) { + ExperimentalCollaboratorResponse collabResponse = new ExperimentalCollaboratorResponse(); + collabResponse.setActive(active); + collabResponse.setEmail(collabRoleUser.getUser().getEmail()); + collabResponse.setName(collabRoleUser.getUser().getName()); + collabResponse.setProgramUserId(collabRoleUser.getId()); + collabResponse.setCollaboratorId(collaboratorId); + collaboratorResponses.add(collabResponse); } } - //wait what *is* response type - //model ExperimentalCollaboratorResponse - - - //biuser has name and email - //program_user_role has id, user_id - - //experimentProgramUserRoleEntity with some stuff appended on - List metadataStatus = new ArrayList<>(); metadataStatus.add(new Status(StatusCode.INFO, "Successful Query")); //TODO: paging Pagination pagination = new Pagination(collaborators.size(), collaborators.size(), 1, 0); Metadata metadata = new Metadata(pagination, metadataStatus); - Response> response = new Response(metadata, new DataResponse<>(collaborators)); + //todo check response type + Response>> response = new Response(metadata, new DataResponse<>(collaboratorResponses)); return HttpResponse.ok(response); } catch (Exception e) { log.info(e.getMessage(), e); - HttpResponse response = HttpResponse.status(HttpStatus.INTERNAL_SERVER_ERROR, "todo").contentType(MediaType.TEXT_PLAIN).body("todo"); + HttpResponse response = HttpResponse.serverError(); return response; } - /* - -Response: -[ - { - "id": UUID, collaboratorId - "active": Boolean, - "userId": UUID,programUserId - "name": String, - "email": String - }, - { - "id": UUID, - "active": Boolean, - "userId": UUID, - "name": String, - "email": String - } -] - */ } From 29b28ac127cf9e2a87034b91331239d2a67a52d3 Mon Sep 17 00:00:00 2001 From: HMS17 Date: Thu, 15 Aug 2024 13:05:30 -0400 Subject: [PATCH 09/30] [BI-2256] - Experimental Collaborator BI-API Changes --- .../v1/controller/ExperimentController.java | 122 +++++++++++++++++- 1 file changed, 121 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java b/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java index 77214c9cf..01158e763 100644 --- a/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java +++ b/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java @@ -10,16 +10,20 @@ import io.micronaut.security.rules.SecurityRule; import lombok.extern.slf4j.Slf4j; import org.brapi.client.v2.model.exceptions.ApiException; +import org.breedinginsight.api.auth.AuthenticatedUser; import org.breedinginsight.api.auth.ProgramSecured; +import org.breedinginsight.api.auth.ProgramSecuredRole; import org.breedinginsight.api.auth.ProgramSecuredRoleGroup; import org.breedinginsight.api.model.v1.request.SubEntityDatasetRequest; import org.breedinginsight.api.model.v1.response.Response; import org.breedinginsight.brapi.v2.model.request.query.ExperimentExportQuery; import org.breedinginsight.brapi.v2.services.BrAPITrialService; +import org.breedinginsight.dao.db.tables.pojos.ExperimentProgramUserRoleEntity; import org.breedinginsight.model.Dataset; import org.breedinginsight.model.DatasetMetadata; import org.breedinginsight.model.DownloadFile; import org.breedinginsight.model.Program; +import org.breedinginsight.services.ExperimentalCollaboratorService; import org.breedinginsight.services.ProgramService; import org.breedinginsight.services.exceptions.DoesNotExistException; import org.breedinginsight.services.exceptions.UnprocessableEntityException; @@ -38,12 +42,14 @@ public class ExperimentController { private final BrAPITrialService experimentService; private final ExperimentQueryMapper experimentQueryMapper; private final ProgramService programService; + private final ExperimentalCollaboratorService experimentalCollaboratorService; @Inject - public ExperimentController(BrAPITrialService experimentService, ExperimentQueryMapper experimentQueryMapper, ProgramService programService) { + public ExperimentController(BrAPITrialService experimentService, ExperimentQueryMapper experimentQueryMapper, ProgramService programService, ExperimentalCollaboratorService experimentalCollaboratorService) { this.experimentService = experimentService; this.experimentQueryMapper = experimentQueryMapper; this.programService = programService; + this.experimentalCollaboratorService = experimentalCollaboratorService; } @Get("/${micronaut.bi.api.version}/programs/{programId}/experiments/{experimentId}/export{?queryParams*}") @@ -147,4 +153,118 @@ public HttpResponse>> getDatasets( return HttpResponse.ok(response); } + + /** + * Adds a record to the experiment_program_user_role table + * @param programId + * @param experimentId + * @param userId the UUID of the experimental collaborator + */ + @Post("/${micronaut.bi.api.version}/programs/{programId}/experiments/{experimentId}/collaborators") + @ProgramSecured(roles = {ProgramSecuredRole.PROGRAM_ADMIN, ProgramSecuredRole.SYSTEM_ADMIN}) + @Produces(MediaType.APPLICATION_JSON) + public HttpResponse> createExperimentalCollaborator( + @PathVariable("programId") UUID programId, + @PathVariable("experimentId") UUID experimentId, + @Body @Valid UUID userId + ) { + try { + Optional programOptional = programService.getById(programId); + if (programOptional.isEmpty()) { + return HttpResponse.status(HttpStatus.NOT_FOUND, "Program does not exist"); + } + //todo clarify body + //userId for downstream method the user creating + //programUserRoleId the experimental collaborator + + //AuthenticatedUser actingUser = securityService.getUser(); + + UUID programUserRoleId = userId; + + Response response = new Response(experimentalCollaboratorService.createExperimentalCollaborator(programUserRoleId,experimentId,userId)); + return HttpResponse.ok(response); + } catch (Exception e){ + log.info(e.getMessage()); + return HttpResponse.status(HttpStatus.UNPROCESSABLE_ENTITY, e.getMessage()); + } + + } + + /** + * Returns an array of collaborators for given experiment filterable using the active query parameter + * @param programId + * @param experimentId + * @param active + */ + @Get("/${micronaut.bi.api.version}/programs/{programId}/experiments/{experimentId}/collaborators?active=true/false") + @ProgramSecured(roles = {ProgramSecuredRole.PROGRAM_ADMIN, ProgramSecuredRole.SYSTEM_ADMIN}) + @Produces(MediaType.APPLICATION_JSON) + public HttpResponse>> getExperimentalCollaborators( + @PathVariable("programId") UUID programId, + @PathVariable("experimentId") UUID experimentId, + @QueryValue(defaultValue = "true") Boolean active + ) { + //todo confirm what default of active should be/if there should be a default + + try { + Program program = programService.getById(programId).orElseThrow(() -> new DoesNotExistException("Program does not exist")); + Response> response = new Response(experimentalCollaboratorService.getExperimentalCollaborators(experimentId)); + //todo filter by program and active + return HttpResponse.ok(response); + } catch (Exception e) { + log.info(e.getMessage(), e); + HttpResponse response = HttpResponse.status(HttpStatus.INTERNAL_SERVER_ERROR, "todo").contentType(MediaType.TEXT_PLAIN).body("todo"); + return response; + } + /* + active = true: program users with the Experimental Collaborator role who have been added as a collaborator to this experiment + + active = false: program users with the Experimental Collaborator role who have not been added as a collaborator to this experiment + + Includes name and email as a convenience to the front end to avoid making another api call + +Response: +[ + { + "id": UUID, + "active": Boolean, + "userId": UUID, + "name": String, + "email": String + }, + { + "id": UUID, + "active": Boolean, + "userId": UUID, + "name": String, + "email": String + } +] + */ + + } + + /** + * Removes record from experiment_program_user_role table + * @param programId + * @param experimentId + * @param collaboratorId + */ + @Delete("/${micronaut.bi.api.version}/programs/{programId}/experiments/{experimentId}/collaborators/{collaboratorId}") + @ProgramSecured(roles = {ProgramSecuredRole.PROGRAM_ADMIN, ProgramSecuredRole.SYSTEM_ADMIN}) + @Produces(MediaType.APPLICATION_JSON) + public HttpResponse deleteExperimentalCollaborator( + @PathVariable("programId") UUID programId, + @PathVariable("experimentId") UUID experimentId, + @PathVariable("collaboratorId") UUID collaboratorId + ) { + try { + experimentalCollaboratorService.deleteExperimentalCollaborator(collaboratorId); + return HttpResponse.ok(); + } catch (Exception e) { + log.error("Error deleting experimental collaborator.\n\tprogramId: " + programId + "\n\texperimentId: " + experimentId + "\n\tcollaboratorId: " + collaboratorId); + throw e; + } + + } } From ef7dd26248822182471007d06f89d18af1014856 Mon Sep 17 00:00:00 2001 From: Nick <53413353+nickpalladino@users.noreply.github.com> Date: Thu, 15 Aug 2024 17:02:33 -0400 Subject: [PATCH 10/30] Added first GET collaborators test and updated controller method --- .../v1/controller/ExperimentController.java | 26 +++++-- .../ExperimentControllerIntegrationTest.java | 67 +++++++++++++++++++ 2 files changed, 86 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java b/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java index 01158e763..1713e2386 100644 --- a/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java +++ b/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java @@ -15,14 +15,16 @@ import org.breedinginsight.api.auth.ProgramSecuredRole; import org.breedinginsight.api.auth.ProgramSecuredRoleGroup; import org.breedinginsight.api.model.v1.request.SubEntityDatasetRequest; +import org.breedinginsight.api.model.v1.response.DataResponse; import org.breedinginsight.api.model.v1.response.Response; +import org.breedinginsight.api.model.v1.response.metadata.Metadata; +import org.breedinginsight.api.model.v1.response.metadata.Pagination; +import org.breedinginsight.api.model.v1.response.metadata.Status; +import org.breedinginsight.api.model.v1.response.metadata.StatusCode; import org.breedinginsight.brapi.v2.model.request.query.ExperimentExportQuery; import org.breedinginsight.brapi.v2.services.BrAPITrialService; import org.breedinginsight.dao.db.tables.pojos.ExperimentProgramUserRoleEntity; -import org.breedinginsight.model.Dataset; -import org.breedinginsight.model.DatasetMetadata; -import org.breedinginsight.model.DownloadFile; -import org.breedinginsight.model.Program; +import org.breedinginsight.model.*; import org.breedinginsight.services.ExperimentalCollaboratorService; import org.breedinginsight.services.ProgramService; import org.breedinginsight.services.exceptions.DoesNotExistException; @@ -31,6 +33,7 @@ import javax.inject.Inject; import javax.validation.Valid; +import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.UUID; @@ -196,10 +199,10 @@ public HttpResponse> createExperimenta * @param experimentId * @param active */ - @Get("/${micronaut.bi.api.version}/programs/{programId}/experiments/{experimentId}/collaborators?active=true/false") + @Get("/${micronaut.bi.api.version}/programs/{programId}/experiments/{experimentId}/collaborators{?active}") @ProgramSecured(roles = {ProgramSecuredRole.PROGRAM_ADMIN, ProgramSecuredRole.SYSTEM_ADMIN}) @Produces(MediaType.APPLICATION_JSON) - public HttpResponse>> getExperimentalCollaborators( + public HttpResponse>> getExperimentalCollaborators( @PathVariable("programId") UUID programId, @PathVariable("experimentId") UUID experimentId, @QueryValue(defaultValue = "true") Boolean active @@ -208,8 +211,17 @@ public HttpResponse>> getExperime try { Program program = programService.getById(programId).orElseThrow(() -> new DoesNotExistException("Program does not exist")); - Response> response = new Response(experimentalCollaboratorService.getExperimentalCollaborators(experimentId)); + List collaborators = experimentalCollaboratorService.getExperimentalCollaborators(experimentId); + //Response> response = new Response(experimentalCollaboratorService.getExperimentalCollaborators(experimentId)); //todo filter by program and active + + List metadataStatus = new ArrayList<>(); + metadataStatus.add(new Status(StatusCode.INFO, "Successful Query")); + //TODO: paging + Pagination pagination = new Pagination(collaborators.size(), collaborators.size(), 1, 0); + Metadata metadata = new Metadata(pagination, metadataStatus); + + Response> response = new Response(metadata, new DataResponse<>(collaborators)); return HttpResponse.ok(response); } catch (Exception e) { log.info(e.getMessage(), e); diff --git a/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java b/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java index 7931ff587..c687d83c8 100644 --- a/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java +++ b/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java @@ -43,6 +43,7 @@ import org.junit.jupiter.api.*; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.ValueSource; import tech.tablesaw.api.ColumnType; import tech.tablesaw.api.Row; import tech.tablesaw.api.Table; @@ -52,6 +53,7 @@ import java.util.*; import java.util.stream.Collectors; import static io.micronaut.http.HttpRequest.*; +import static org.junit.Assert.assertNotEquals; import static org.junit.jupiter.api.Assertions.*; @MicronautTest @@ -348,6 +350,71 @@ void downloadSubEntityDataset(String extension) { parseAndCheck(plantBodyStream, extension, false, plantRows, false, 23); } + /** + * Tests for Experimental Collaborator endpoints + * + * Create Experimental Collaborator + * + * Remove Experimental Collaborator + * + * Get Experimental Collaborators None + * GIVEN GET /v1/programs/{programId}/experiments/{experimentId}/collaborators?active=true|false + * WHEN no users have been added as experiment collaborators + * AND no program users with Experimental Collaborator role exist in program + * THEN response should be an empty array regardless of active query parameter value + * + * Get Experimental Collaborators No Active + * GIVEN GET /v1/programs/{programId}/experiments/{experimentId}/collaborators?active=true|false + * WHEN no users have been added as experiment collaborators + * AND one or more program users with Experimental Collaborator role exist in program + * THEN response should be: + * empty array when active=true + * array with program user when active=false + * + * Get Experimental Collaborators Active + * GIVEN GET /v1/programs/{programId}/experiments/{experimentId}/collaborators?active=true|false + * WHEN program user has been added to experiment as collaborator + * AND program user with Experimental Collaborator role exists in program + * THEN response should be: + * array with program user when active=true + * empty array when active=false + * + * Get Experimental Collaborators Deactivated from Program + * GIVEN GET /v1/programs/{programId}/experiments/{experimentId}/collaborators?active=true|false + * WHEN program user has been added to experiment as collaborator + * AND after being added as a collaborator, program user is deactivated from program + * THEN response should be empty array regardless of active query parameter value (assumes single user) + * + */ + + /** + * Get Experimental Collaborators None + * GIVEN GET /v1/programs/{programId}/experiments/{experimentId}/collaborators?active=true|false + * WHEN no users have been added as experiment collaborators + * AND no program users with Experimental Collaborator role exist in program + * THEN response should be an empty array regardless of active query parameter value + * + * test-registered-user has Program Administration role in program + */ + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void getExperimentalCollaboratorsNone(boolean active) { + + Flowable> call = client.exchange( + GET(String.format("/programs/%s/experiments/%s/collaborators?active=%s", program.getId().toString(), experimentId, active)) + .contentType(MediaType.APPLICATION_JSON) + .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(0, data.size()); + } + + private List> buildSubEntityRows(List> topLevelRows, String entityName, int repeatedMeasures) { List> plantRows = new ArrayList<>(); for (Map row : topLevelRows) { From 90b976de0b6daeca1e4b12c822cb6d4c2efa1ee8 Mon Sep 17 00:00:00 2001 From: HMS17 Date: Fri, 16 Aug 2024 16:12:14 -0400 Subject: [PATCH 11/30] [BI-2256] - Small refactoring, endpoint progress --- .../v1/controller/ExperimentController.java | 75 +++++++++++-------- .../daos/ExperimentalCollaboratorDAO.java | 6 +- .../ExperimentalCollaboratorService.java | 6 +- 3 files changed, 50 insertions(+), 37 deletions(-) diff --git a/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java b/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java index 1713e2386..cf37689b2 100644 --- a/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java +++ b/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java @@ -10,10 +10,7 @@ import io.micronaut.security.rules.SecurityRule; import lombok.extern.slf4j.Slf4j; import org.brapi.client.v2.model.exceptions.ApiException; -import org.breedinginsight.api.auth.AuthenticatedUser; -import org.breedinginsight.api.auth.ProgramSecured; -import org.breedinginsight.api.auth.ProgramSecuredRole; -import org.breedinginsight.api.auth.ProgramSecuredRoleGroup; +import org.breedinginsight.api.auth.*; import org.breedinginsight.api.model.v1.request.SubEntityDatasetRequest; import org.breedinginsight.api.model.v1.response.DataResponse; import org.breedinginsight.api.model.v1.response.Response; @@ -46,13 +43,15 @@ public class ExperimentController { private final ExperimentQueryMapper experimentQueryMapper; private final ProgramService programService; private final ExperimentalCollaboratorService experimentalCollaboratorService; + private final SecurityService securityService; @Inject - public ExperimentController(BrAPITrialService experimentService, ExperimentQueryMapper experimentQueryMapper, ProgramService programService, ExperimentalCollaboratorService experimentalCollaboratorService) { + public ExperimentController(BrAPITrialService experimentService, ExperimentQueryMapper experimentQueryMapper, ProgramService programService, ExperimentalCollaboratorService experimentalCollaboratorService, SecurityService securityService) { this.experimentService = experimentService; this.experimentQueryMapper = experimentQueryMapper; this.programService = programService; this.experimentalCollaboratorService = experimentalCollaboratorService; + this.securityService = securityService; } @Get("/${micronaut.bi.api.version}/programs/{programId}/experiments/{experimentId}/export{?queryParams*}") @@ -138,7 +137,7 @@ public HttpResponse> createSubEntityDataset( * @param experimentId The UUID of the experiment. * @return An HttpResponse with a Response object containing a list of DatasetMetadata. * @throws DoesNotExistException if the program does not exist. - * @throws ApiException if an error occurs while retrieving the datasets. + * @throws ApiException if an error occurs while retrieving the datasets.UserId */ @Get("/${micronaut.bi.api.version}/programs/{programId}/experiments/{experimentId}/datasets") @ProgramSecured(roleGroups = {ProgramSecuredRoleGroup.ALL}) @@ -159,9 +158,10 @@ public HttpResponse>> getDatasets( /** * Adds a record to the experiment_program_user_role table - * @param programId - * @param experimentId - * @param userId the UUID of the experimental collaborator + * @param programId The UUID of the program + * @param experimentId The UUID of the experiment + * @param programUserRoleId The UUID of the program user + * @return HttpResponse containing the newly created ExperimentProgramUserRoleEntity */ @Post("/${micronaut.bi.api.version}/programs/{programId}/experiments/{experimentId}/collaborators") @ProgramSecured(roles = {ProgramSecuredRole.PROGRAM_ADMIN, ProgramSecuredRole.SYSTEM_ADMIN}) @@ -169,22 +169,19 @@ public HttpResponse>> getDatasets( public HttpResponse> createExperimentalCollaborator( @PathVariable("programId") UUID programId, @PathVariable("experimentId") UUID experimentId, - @Body @Valid UUID userId + @Body @Valid UUID programUserRoleId ) { try { Optional programOptional = programService.getById(programId); if (programOptional.isEmpty()) { return HttpResponse.status(HttpStatus.NOT_FOUND, "Program does not exist"); } - //todo clarify body - //userId for downstream method the user creating - //programUserRoleId the experimental collaborator - //AuthenticatedUser actingUser = securityService.getUser(); + //get active user creating the collaborator + AuthenticatedUser createdByUser = securityService.getUser(); + UUID createdByUserId = createdByUser.getId(); - UUID programUserRoleId = userId; - - Response response = new Response(experimentalCollaboratorService.createExperimentalCollaborator(programUserRoleId,experimentId,userId)); + Response response = new Response(experimentalCollaboratorService.createExperimentalCollaborator(programUserRoleId,experimentId,createdByUserId)); return HttpResponse.ok(response); } catch (Exception e){ log.info(e.getMessage()); @@ -195,9 +192,11 @@ public HttpResponse> createExperimenta /** * Returns an array of collaborators for given experiment filterable using the active query parameter - * @param programId - * @param experimentId - * @param active + * @param programId The UUID of the program + * @param experimentId The UUID of the experiment + * @param active true if querying for collaborators added as a collaborator to the experiment, false if querying for collaborators not added + * @return + * Response includes name and email as a convenience to the front end to avoid making another api call */ @Get("/${micronaut.bi.api.version}/programs/{programId}/experiments/{experimentId}/collaborators{?active}") @ProgramSecured(roles = {ProgramSecuredRole.PROGRAM_ADMIN, ProgramSecuredRole.SYSTEM_ADMIN}) @@ -211,9 +210,26 @@ public HttpResponse>> get try { Program program = programService.getById(programId).orElseThrow(() -> new DoesNotExistException("Program does not exist")); + + //Get experimental collaborators associated with the experiment List collaborators = experimentalCollaboratorService.getExperimentalCollaborators(experimentId); + + //Get all program users with experimental collaborator role + //List collabRoleUsers = programService. + + if (active){ + //return users with experimental collaborator role associated with this experiment + } else { + //return users with experimental collaborator role NOT associated with this experiment + } + + //may end up needing helper method + + //Response> response = new Response(experimentalCollaboratorService.getExperimentalCollaborators(experimentId)); - //todo filter by program and active + + //programuserservice, programusers with expcollab role and then could collaborators on experiment + List metadataStatus = new ArrayList<>(); metadataStatus.add(new Status(StatusCode.INFO, "Successful Query")); @@ -229,18 +245,13 @@ public HttpResponse>> get return response; } /* - active = true: program users with the Experimental Collaborator role who have been added as a collaborator to this experiment - - active = false: program users with the Experimental Collaborator role who have not been added as a collaborator to this experiment - - Includes name and email as a convenience to the front end to avoid making another api call Response: [ { - "id": UUID, + "id": UUID, collaboratorId "active": Boolean, - "userId": UUID, + "userId": UUID,programUserId "name": String, "email": String }, @@ -258,9 +269,10 @@ public HttpResponse>> get /** * Removes record from experiment_program_user_role table - * @param programId - * @param experimentId - * @param collaboratorId + * @param programId The UUID of the program + * @param experimentId The UUID of the experiment + * @param collaboratorId The UUID of the collaborator, referring to a unique experiment-program user role combo in the experiment_program_user_role table + * @return A Http Response */ @Delete("/${micronaut.bi.api.version}/programs/{programId}/experiments/{experimentId}/collaborators/{collaboratorId}") @ProgramSecured(roles = {ProgramSecuredRole.PROGRAM_ADMIN, ProgramSecuredRole.SYSTEM_ADMIN}) @@ -271,6 +283,7 @@ public HttpResponse deleteExperimentalCollaborator( @PathVariable("collaboratorId") UUID collaboratorId ) { try { + //todo double check this endpoint would be getting the collaboratorId and not the programUserRoleId experimentalCollaboratorService.deleteExperimentalCollaborator(collaboratorId); return HttpResponse.ok(); } catch (Exception e) { diff --git a/src/main/java/org/breedinginsight/daos/ExperimentalCollaboratorDAO.java b/src/main/java/org/breedinginsight/daos/ExperimentalCollaboratorDAO.java index 0187c55b5..ccf3741ee 100644 --- a/src/main/java/org/breedinginsight/daos/ExperimentalCollaboratorDAO.java +++ b/src/main/java/org/breedinginsight/daos/ExperimentalCollaboratorDAO.java @@ -43,7 +43,7 @@ public ExperimentalCollaboratorDAO(Configuration config, DSLContext dsl) { this.dsl = dsl; } - public ExperimentProgramUserRoleEntity create(UUID experimentId, UUID programUserRoleId, UUID userId) { + public ExperimentProgramUserRoleEntity create(UUID experimentId, UUID programUserRoleId, UUID createdByUserId) { return dsl.insertInto(EXPERIMENT_PROGRAM_USER_ROLE) .columns(EXPERIMENT_PROGRAM_USER_ROLE.EXPERIMENT_ID, EXPERIMENT_PROGRAM_USER_ROLE.PROGRAM_USER_ROLE_ID, @@ -53,9 +53,9 @@ public ExperimentProgramUserRoleEntity create(UUID experimentId, UUID programUse EXPERIMENT_PROGRAM_USER_ROLE.UPDATED_AT) .values(experimentId, programUserRoleId, - userId, + createdByUserId, OffsetDateTime.now(), - userId, + createdByUserId, OffsetDateTime.now()) .returning(EXPERIMENT_PROGRAM_USER_ROLE.fields()) .fetchOneInto(ExperimentProgramUserRoleEntity.class); diff --git a/src/main/java/org/breedinginsight/services/ExperimentalCollaboratorService.java b/src/main/java/org/breedinginsight/services/ExperimentalCollaboratorService.java index f6fe07390..f0349c9e9 100644 --- a/src/main/java/org/breedinginsight/services/ExperimentalCollaboratorService.java +++ b/src/main/java/org/breedinginsight/services/ExperimentalCollaboratorService.java @@ -37,8 +37,8 @@ public ExperimentalCollaboratorService(ExperimentalCollaboratorDAO experimentalC this.experimentalCollaboratorDAO = experimentalCollaboratorDAO; } - public ExperimentProgramUserRoleEntity createExperimentalCollaborator(UUID programUserRoleId, UUID experimentId, UUID userId) { - return this.experimentalCollaboratorDAO.create(experimentId, programUserRoleId, userId); + public ExperimentProgramUserRoleEntity createExperimentalCollaborator(UUID programUserRoleId, UUID experimentId, UUID createdByUserId) { + return this.experimentalCollaboratorDAO.create(experimentId, programUserRoleId, createdByUserId); } public List getExperimentalCollaborators(UUID experimentId) { @@ -47,7 +47,7 @@ public List getExperimentalCollaborators(UUID e } public void deleteExperimentalCollaborator(UUID collaboratorId) { - // Note: collaboratorId is the PK of the experiment_program_user_role table. + // Note: collaboratorId is the primary key of the experiment_program_user_role table. this.experimentalCollaboratorDAO.deleteById(collaboratorId); } } From 3ad6c1b87dd2e8c7a8e93f408e2458fdf6d9d41b Mon Sep 17 00:00:00 2001 From: HMS17 Date: Fri, 16 Aug 2024 18:08:59 -0400 Subject: [PATCH 12/30] [BI-2256] - Working on GET, RoleService helper method --- .../v1/controller/ExperimentController.java | 43 +++++++++++++------ .../breedinginsight/services/RoleService.java | 12 ++++++ 2 files changed, 43 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java b/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java index cf37689b2..cb21ae20d 100644 --- a/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java +++ b/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java @@ -24,6 +24,8 @@ import org.breedinginsight.model.*; import org.breedinginsight.services.ExperimentalCollaboratorService; import org.breedinginsight.services.ProgramService; +import org.breedinginsight.services.ProgramUserService; +import org.breedinginsight.services.RoleService; import org.breedinginsight.services.exceptions.DoesNotExistException; import org.breedinginsight.services.exceptions.UnprocessableEntityException; import org.breedinginsight.utilities.response.mappers.ExperimentQueryMapper; @@ -44,14 +46,18 @@ public class ExperimentController { private final ProgramService programService; private final ExperimentalCollaboratorService experimentalCollaboratorService; private final SecurityService securityService; + private final ProgramUserService programUserService; + private final RoleService roleService; @Inject - public ExperimentController(BrAPITrialService experimentService, ExperimentQueryMapper experimentQueryMapper, ProgramService programService, ExperimentalCollaboratorService experimentalCollaboratorService, SecurityService securityService) { + public ExperimentController(BrAPITrialService experimentService, ExperimentQueryMapper experimentQueryMapper, ProgramService programService, ExperimentalCollaboratorService experimentalCollaboratorService, SecurityService securityService, ProgramUserService programUserService, RoleService roleService) { this.experimentService = experimentService; this.experimentQueryMapper = experimentQueryMapper; this.programService = programService; this.experimentalCollaboratorService = experimentalCollaboratorService; this.securityService = securityService; + this.programUserService = programUserService; + this.roleService = roleService; } @Get("/${micronaut.bi.api.version}/programs/{programId}/experiments/{experimentId}/export{?queryParams*}") @@ -209,27 +215,40 @@ public HttpResponse>> get //todo confirm what default of active should be/if there should be a default try { - Program program = programService.getById(programId).orElseThrow(() -> new DoesNotExistException("Program does not exist")); + //Program program = programService.getById(programId).orElseThrow(() -> new DoesNotExistException("Program does not exist")); //Get experimental collaborators associated with the experiment List collaborators = experimentalCollaboratorService.getExperimentalCollaborators(experimentId); - //Get all program users with experimental collaborator role - //List collabRoleUsers = programService. + //Get roleId for experimental collaborator role + Role experimentalCollabRole = roleService.getRoleByDomain(ProgramSecuredRole.EXPERIMENTAL_COLLABORATOR.toString()).get(); + UUID roleId = experimentalCollabRole.getId(); - if (active){ - //return users with experimental collaborator role associated with this experiment - } else { - //return users with experimental collaborator role NOT associated with this experiment + //Get all program users with experimental collaborator role + List collabRoleUsers = programUserService.getProgramUsersByRole(programId, roleId); + + //let's start with case of finding users not assoc with experiment + //need new fancy model maybe + + Boolean isACollaborator = false; + for (ProgramUser collabRoleUser : collabRoleUsers) { + //if collabRoleUser.getUser().getId(); + //should be something more efficient, right? + if (active){ + //return users with experimental collaborator role associated with this experiment + } else { + //return users with experimental collaborator role NOT associated with this experiment + } } - //may end up needing helper method - + //wait what *is* response type + //model ExperimentalCollaboratorResponse - //Response> response = new Response(experimentalCollaboratorService.getExperimentalCollaborators(experimentId)); - //programuserservice, programusers with expcollab role and then could collaborators on experiment + //biuser has name and email + //program_user_role has id, user_id + //experimentProgramUserRoleEntity with some stuff appended on List metadataStatus = new ArrayList<>(); metadataStatus.add(new Status(StatusCode.INFO, "Successful Query")); diff --git a/src/main/java/org/breedinginsight/services/RoleService.java b/src/main/java/org/breedinginsight/services/RoleService.java index ecc9fc4e5..63165fdf0 100644 --- a/src/main/java/org/breedinginsight/services/RoleService.java +++ b/src/main/java/org/breedinginsight/services/RoleService.java @@ -17,6 +17,9 @@ package org.breedinginsight.services; +import io.micronaut.http.HttpResponse; +import io.micronaut.http.HttpStatus; +import io.micronaut.http.MediaType; import lombok.extern.slf4j.Slf4j; import org.breedinginsight.dao.db.tables.daos.RoleDao; import org.breedinginsight.dao.db.tables.pojos.RoleEntity; @@ -66,4 +69,13 @@ public List getRolesByIds(List roleIds) { return roles; } + public Optional getRoleByDomain(String domain) { + RoleEntity role = dao.fetchByDomain(domain).get(0); + if (role == null) { + return Optional.empty(); + } + + return Optional.of(new Role(role)); + } + } From 3e61b683318a8ff6074e5936d07d0257c573df91 Mon Sep 17 00:00:00 2001 From: Nick <53413353+nickpalladino@users.noreply.github.com> Date: Mon, 19 Aug 2024 10:17:57 -0400 Subject: [PATCH 13/30] Added second GET test and some user setup and teardown --- .../org/breedinginsight/utilities/out.csv | 8 +++ .../ExperimentControllerIntegrationTest.java | 49 ++++++++++++++++++- ...amSecuredAnnotationRuleIntegrationTest.sql | 22 +++++++++ 3 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/breedinginsight/utilities/out.csv diff --git a/src/main/java/org/breedinginsight/utilities/out.csv b/src/main/java/org/breedinginsight/utilities/out.csv new file mode 100644 index 000000000..d5f869930 --- /dev/null +++ b/src/main/java/org/breedinginsight/utilities/out.csv @@ -0,0 +1,8 @@ +genotype,genotype_uncertainty,plot,plot_uncertainty,height,height_uncertainty,rating,rating_uncertainty,notes,notes_uncertainty +Apple,FALSE,1001,FALSE,7,FALSE,1,FALSE,Bad germ,FALSE +Xnana,FALSE,1002,FALSE,8.2,TRUE,2,FALSE,,TRUE +Clementine,FALSE,1003,FALSE,128,TRUE,1,FALSE,missing,FALSE +Durian,FALSE,1004,FALSE,8,TRUE,3,FALSE,,TRUE +Elephant,FALSE,1005,FALSE,6.38,FALSE,4,FALSE,missing,FALSE +Framboise,FALSE,1006,FALSE,10,FALSE,5,FALSE,,TRUE +Grapes,FALSE,1007,FALSE,3,FALSE,6,FALSE,NA,FALSE \ No newline at end of file diff --git a/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java b/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java index c687d83c8..25f122af0 100644 --- a/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java +++ b/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java @@ -40,6 +40,7 @@ import org.breedinginsight.utilities.DatasetUtil; import org.breedinginsight.utilities.FileUtil; import org.jooq.DSLContext; +import org.junit.Test; import org.junit.jupiter.api.*; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; @@ -67,6 +68,8 @@ public class ExperimentControllerIntegrationTest extends BrAPITest { private final List> rows = new ArrayList<>(); private final List columns = ExperimentFileColumns.getOrderedColumns(); private List traits; + private User testUser; + private User otherTestUser; @Property(name = "brapi.server.reference-source") private String BRAPI_REFERENCE_SOURCE; @@ -101,7 +104,9 @@ void setup() throws Exception { FannyPack brapiFp = FannyPack.fill("src/test/resources/sql/brapi/species.sql"); // Test User - User testUser = userDAO.getUserByOrcId(TestTokenValidator.TEST_USER_ORCID).orElseThrow(Exception::new); + testUser = userDAO.getUserByOrcId(TestTokenValidator.TEST_USER_ORCID).orElseThrow(Exception::new); + otherTestUser = userDAO.getUserByOrcId(TestTokenValidator.OTHER_TEST_USER_ORCID).orElseThrow(Exception::new); + dsl.execute(securityFp.get("InsertSystemRoleAdmin"), testUser.getId().toString()); // Species @@ -414,6 +419,48 @@ public void getExperimentalCollaboratorsNone(boolean active) { assertEquals(0, data.size()); } + /** + * Get Experimental Collaborators No Active + * GIVEN GET /v1/programs/{programId}/experiments/{experimentId}/collaborators?active=true|false + * WHEN no users have been added as experiment collaborators + * AND one or more program users with Experimental Collaborator role exist in program + * THEN response should be: + * empty array when active=true + * array with program user when active=false + */ + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void getExperimentalCollaboratorsNoActive(boolean active) { + + // add a program user with the experimental collaborator role + FannyPack securityFp = FannyPack.fill("src/test/resources/sql/ProgramSecuredAnnotationRuleIntegrationTest.sql"); + dsl.execute(securityFp.get("InsertProgramRolesExperimentalCollaborator"), otherTestUser.getId().toString(), program.getId()); + + Flowable> call = client.exchange( + GET(String.format("/programs/%s/experiments/%s/collaborators?active=%s", program.getId().toString(), experimentId, active)) + .contentType(MediaType.APPLICATION_JSON) + .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"); + + if (active) { + assertEquals(0, data.size()); + } else { + assertEquals(1, data.size()); + // TODO: check user details + + } + + // delete program user from setup + // NOTE: if test fails this may not be run and could impact other tests results + dsl.execute(securityFp.get("DeleteProgramUser"), otherTestUser.getId().toString()); + + } private List> buildSubEntityRows(List> topLevelRows, String entityName, int repeatedMeasures) { List> plantRows = new ArrayList<>(); diff --git a/src/test/resources/sql/ProgramSecuredAnnotationRuleIntegrationTest.sql b/src/test/resources/sql/ProgramSecuredAnnotationRuleIntegrationTest.sql index 17f08c19d..dc4e40e49 100644 --- a/src/test/resources/sql/ProgramSecuredAnnotationRuleIntegrationTest.sql +++ b/src/test/resources/sql/ProgramSecuredAnnotationRuleIntegrationTest.sql @@ -53,6 +53,28 @@ bi_user join role on role.domain = 'Program Administrator' where bi_user.name = 'system'; +-- name: InsertProgramRolesExperimentalCollaborator + +insert into program_user_role (user_id, program_id, role_id, created_by, updated_by) +select + ?::uuid, ?::uuid, role.id, bi_user.id, bi_user.id +from + bi_user + join role on role.domain = 'Experimental Collaborator' +where bi_user.name = 'system'; + +-- name: DeleteExperimentalCollaboratorProgramUsers + +DELETE FROM program_user_role + USING role +WHERE program_user_role.role_id = role.id + AND role.domain = 'Experimental Collaborator'; + +-- name: DeleteProgramUser + +DELETE FROM program_user_role +WHERE user_id = :id::uuid; + -- name: InsertSystemRoleAdmin insert into system_user_role (bi_user_id, system_role_id, created_by, updated_by) From b584e683688fc249246581e02e8def31c714d826 Mon Sep 17 00:00:00 2001 From: Nick <53413353+nickpalladino@users.noreply.github.com> Date: Mon, 19 Aug 2024 10:19:58 -0400 Subject: [PATCH 14/30] Delete src/main/java/org/breedinginsight/utilities/out.csv --- src/main/java/org/breedinginsight/utilities/out.csv | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 src/main/java/org/breedinginsight/utilities/out.csv diff --git a/src/main/java/org/breedinginsight/utilities/out.csv b/src/main/java/org/breedinginsight/utilities/out.csv deleted file mode 100644 index d5f869930..000000000 --- a/src/main/java/org/breedinginsight/utilities/out.csv +++ /dev/null @@ -1,8 +0,0 @@ -genotype,genotype_uncertainty,plot,plot_uncertainty,height,height_uncertainty,rating,rating_uncertainty,notes,notes_uncertainty -Apple,FALSE,1001,FALSE,7,FALSE,1,FALSE,Bad germ,FALSE -Xnana,FALSE,1002,FALSE,8.2,TRUE,2,FALSE,,TRUE -Clementine,FALSE,1003,FALSE,128,TRUE,1,FALSE,missing,FALSE -Durian,FALSE,1004,FALSE,8,TRUE,3,FALSE,,TRUE -Elephant,FALSE,1005,FALSE,6.38,FALSE,4,FALSE,missing,FALSE -Framboise,FALSE,1006,FALSE,10,FALSE,5,FALSE,,TRUE -Grapes,FALSE,1007,FALSE,3,FALSE,6,FALSE,NA,FALSE \ No newline at end of file From 6556601aa3ce9f5d992856211fb02a3d1b42509a Mon Sep 17 00:00:00 2001 From: Nick <53413353+nickpalladino@users.noreply.github.com> Date: Mon, 19 Aug 2024 16:49:43 -0400 Subject: [PATCH 15/30] Added test for POST with invalid program user id and updated request body --- .../ExperimentCollaboratorRequest.java | 19 +++++++ .../v1/controller/ExperimentController.java | 9 ++-- .../ExperimentControllerIntegrationTest.java | 51 +++++++++++-------- 3 files changed, 55 insertions(+), 24 deletions(-) create mode 100644 src/main/java/org/breedinginsight/api/model/v1/request/ExperimentCollaboratorRequest.java diff --git a/src/main/java/org/breedinginsight/api/model/v1/request/ExperimentCollaboratorRequest.java b/src/main/java/org/breedinginsight/api/model/v1/request/ExperimentCollaboratorRequest.java new file mode 100644 index 000000000..85a1e43b9 --- /dev/null +++ b/src/main/java/org/breedinginsight/api/model/v1/request/ExperimentCollaboratorRequest.java @@ -0,0 +1,19 @@ +package org.breedinginsight.api.model.v1.request; + +import io.micronaut.core.annotation.Introspected; +import lombok.*; + +import javax.validation.constraints.NotBlank; +import java.util.UUID; + +@Getter +@Setter +@Builder +@ToString +@AllArgsConstructor +@NoArgsConstructor +@Introspected +public class ExperimentCollaboratorRequest { + @NotBlank + private UUID programUserId; +} diff --git a/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java b/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java index cb21ae20d..64e24c3ab 100644 --- a/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java +++ b/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java @@ -11,6 +11,7 @@ import lombok.extern.slf4j.Slf4j; import org.brapi.client.v2.model.exceptions.ApiException; import org.breedinginsight.api.auth.*; +import org.breedinginsight.api.model.v1.request.ExperimentCollaboratorRequest; import org.breedinginsight.api.model.v1.request.SubEntityDatasetRequest; import org.breedinginsight.api.model.v1.response.DataResponse; import org.breedinginsight.api.model.v1.response.Response; @@ -166,7 +167,7 @@ public HttpResponse>> getDatasets( * Adds a record to the experiment_program_user_role table * @param programId The UUID of the program * @param experimentId The UUID of the experiment - * @param programUserRoleId The UUID of the program user + * @param programUserId The UUID of the program user * @return HttpResponse containing the newly created ExperimentProgramUserRoleEntity */ @Post("/${micronaut.bi.api.version}/programs/{programId}/experiments/{experimentId}/collaborators") @@ -175,7 +176,7 @@ public HttpResponse>> getDatasets( public HttpResponse> createExperimentalCollaborator( @PathVariable("programId") UUID programId, @PathVariable("experimentId") UUID experimentId, - @Body @Valid UUID programUserRoleId + @Body @Valid ExperimentCollaboratorRequest request ) { try { Optional programOptional = programService.getById(programId); @@ -186,8 +187,8 @@ public HttpResponse> createExperimenta //get active user creating the collaborator AuthenticatedUser createdByUser = securityService.getUser(); UUID createdByUserId = createdByUser.getId(); - - Response response = new Response(experimentalCollaboratorService.createExperimentalCollaborator(programUserRoleId,experimentId,createdByUserId)); + UUID programUserId = request.getProgramUserId(); + Response response = new Response(experimentalCollaboratorService.createExperimentalCollaborator(programUserId,experimentId,createdByUserId)); return HttpResponse.ok(response); } catch (Exception e){ log.info(e.getMessage()); diff --git a/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java b/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java index 25f122af0..3d032b984 100644 --- a/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java +++ b/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java @@ -8,6 +8,7 @@ import io.micronaut.http.MediaType; import io.micronaut.http.client.RxHttpClient; import io.micronaut.http.client.annotation.Client; +import io.micronaut.http.client.exceptions.HttpClientResponseException; import io.micronaut.http.netty.cookies.NettyCookie; import io.micronaut.test.annotation.MicronautTest; import io.reactivex.Flowable; @@ -40,7 +41,6 @@ import org.breedinginsight.utilities.DatasetUtil; import org.breedinginsight.utilities.FileUtil; import org.jooq.DSLContext; -import org.junit.Test; import org.junit.jupiter.api.*; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; @@ -362,19 +362,6 @@ void downloadSubEntityDataset(String extension) { * * Remove Experimental Collaborator * - * Get Experimental Collaborators None - * GIVEN GET /v1/programs/{programId}/experiments/{experimentId}/collaborators?active=true|false - * WHEN no users have been added as experiment collaborators - * AND no program users with Experimental Collaborator role exist in program - * THEN response should be an empty array regardless of active query parameter value - * - * Get Experimental Collaborators No Active - * GIVEN GET /v1/programs/{programId}/experiments/{experimentId}/collaborators?active=true|false - * WHEN no users have been added as experiment collaborators - * AND one or more program users with Experimental Collaborator role exist in program - * THEN response should be: - * empty array when active=true - * array with program user when active=false * * Get Experimental Collaborators Active * GIVEN GET /v1/programs/{programId}/experiments/{experimentId}/collaborators?active=true|false @@ -393,13 +380,37 @@ void downloadSubEntityDataset(String extension) { */ /** - * Get Experimental Collaborators None - * GIVEN GET /v1/programs/{programId}/experiments/{experimentId}/collaborators?active=true|false - * WHEN no users have been added as experiment collaborators - * AND no program users with Experimental Collaborator role exist in program - * THEN response should be an empty array regardless of active query parameter value + * Create Experimental Collaborator Invalid Id + * GIVEN POST /v1/programs/{programId}/experiments/{experimentId}/collaborators + * WHEN an invalid id is passed in the body of the request + * THEN response should be 422 (maybe should be bad request?) + */ + @Test + public void postExperimentalCollaboratorsInvalidId() { + JsonObject requestBody = new JsonObject(); + requestBody.addProperty("programUserId", "f47ac10b-58cc-4372-a567-0e02b2c3d479"); + + Flowable> call = client.exchange( + POST(String.format("/programs/%s/experiments/%s/collaborators", program.getId().toString(), experimentId), requestBody.toString()) + .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()); + } + + /** + * Get Experimental Collaborators None + * GIVEN GET /v1/programs/{programId}/experiments/{experimentId}/collaborators?active=true|false + * WHEN no users have been added as experiment collaborators + * AND no program users with Experimental Collaborator role exist in program + * THEN response should be an empty array regardless of active query parameter value * - * test-registered-user has Program Administration role in program + * test-registered-user has Program Administration role in program */ @ParameterizedTest @ValueSource(booleans = {true, false}) From 4f18253de311143167810d4ca4a0557abe989d2e Mon Sep 17 00:00:00 2001 From: HMS17 Date: Tue, 20 Aug 2024 14:04:19 -0400 Subject: [PATCH 16/30] [BI-2256] - GET method, some other fixes --- .../ExperimentalCollaboratorResponse.java | 45 +++++++++++ .../v1/controller/ExperimentController.java | 74 ++++++++----------- 2 files changed, 76 insertions(+), 43 deletions(-) create mode 100644 src/main/java/org/breedinginsight/api/model/v1/response/ExperimentalCollaboratorResponse.java diff --git a/src/main/java/org/breedinginsight/api/model/v1/response/ExperimentalCollaboratorResponse.java b/src/main/java/org/breedinginsight/api/model/v1/response/ExperimentalCollaboratorResponse.java new file mode 100644 index 000000000..d9a308787 --- /dev/null +++ b/src/main/java/org/breedinginsight/api/model/v1/response/ExperimentalCollaboratorResponse.java @@ -0,0 +1,45 @@ +/* + * See the NOTICE file distributed with this work for additional information + * regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.breedinginsight.api.model.v1.response; + +import lombok.*; +import lombok.experimental.Accessors; + +import javax.validation.constraints.NotNull; +import java.util.UUID; + +@Getter +@Setter +@Accessors(chain=true) +@ToString +@NoArgsConstructor +@AllArgsConstructor +public class ExperimentalCollaboratorResponse { + //is null in case where active=false + private UUID collaboratorId; + @NotNull + private Boolean active; + @NotNull + private UUID programUserId; + @NotNull + private String name; + @NotNull + private String email; + //todo determine notblank vs notnull + +} diff --git a/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java b/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java index 64e24c3ab..2cee30aef 100644 --- a/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java +++ b/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java @@ -14,6 +14,7 @@ import org.breedinginsight.api.model.v1.request.ExperimentCollaboratorRequest; import org.breedinginsight.api.model.v1.request.SubEntityDatasetRequest; import org.breedinginsight.api.model.v1.response.DataResponse; +import org.breedinginsight.api.model.v1.response.ExperimentalCollaboratorResponse; import org.breedinginsight.api.model.v1.response.Response; import org.breedinginsight.api.model.v1.response.metadata.Metadata; import org.breedinginsight.api.model.v1.response.metadata.Pagination; @@ -29,6 +30,7 @@ import org.breedinginsight.services.RoleService; import org.breedinginsight.services.exceptions.DoesNotExistException; import org.breedinginsight.services.exceptions.UnprocessableEntityException; +import org.breedinginsight.utilities.Utilities; import org.breedinginsight.utilities.response.mappers.ExperimentQueryMapper; import javax.inject.Inject; @@ -37,6 +39,7 @@ import java.util.List; import java.util.Optional; import java.util.UUID; +import java.util.stream.Collectors; @Slf4j @Controller @@ -167,7 +170,7 @@ public HttpResponse>> getDatasets( * Adds a record to the experiment_program_user_role table * @param programId The UUID of the program * @param experimentId The UUID of the experiment - * @param programUserId The UUID of the program user + * @param request ExperimentalCollaboratorRequest containing the UUID of the program user to add as a collaborator to the experiemnt * @return HttpResponse containing the newly created ExperimentProgramUserRoleEntity */ @Post("/${micronaut.bi.api.version}/programs/{programId}/experiments/{experimentId}/collaborators") @@ -179,11 +182,18 @@ public HttpResponse> createExperimenta @Body @Valid ExperimentCollaboratorRequest request ) { try { + //Check if program exists Optional programOptional = programService.getById(programId); if (programOptional.isEmpty()) { return HttpResponse.status(HttpStatus.NOT_FOUND, "Program does not exist"); } + //Check if program user exists + Optional programUserOptional = programUserService.getProgramUserbyId(programId, request.getProgramUserId()); + if (programUserOptional.isEmpty()) { + return HttpResponse.status(HttpStatus.NOT_FOUND, "Program user does not exist"); + } + //get active user creating the collaborator AuthenticatedUser createdByUser = securityService.getUser(); UUID createdByUserId = createdByUser.getId(); @@ -208,7 +218,7 @@ public HttpResponse> createExperimenta @Get("/${micronaut.bi.api.version}/programs/{programId}/experiments/{experimentId}/collaborators{?active}") @ProgramSecured(roles = {ProgramSecuredRole.PROGRAM_ADMIN, ProgramSecuredRole.SYSTEM_ADMIN}) @Produces(MediaType.APPLICATION_JSON) - public HttpResponse>> getExperimentalCollaborators( + public HttpResponse>>> getExperimentalCollaborators( @PathVariable("programId") UUID programId, @PathVariable("experimentId") UUID experimentId, @QueryValue(defaultValue = "true") Boolean active @@ -220,6 +230,7 @@ public HttpResponse>> get //Get experimental collaborators associated with the experiment List collaborators = experimentalCollaboratorService.getExperimentalCollaborators(experimentId); + List activeCollaboratorIds = collaborators.stream().map((ExperimentProgramUserRoleEntity::getProgramUserRoleId)).collect(Collectors.toList()); //Get roleId for experimental collaborator role Role experimentalCollabRole = roleService.getRoleByDomain(ProgramSecuredRole.EXPERIMENTAL_COLLABORATOR.toString()).get(); @@ -227,63 +238,40 @@ public HttpResponse>> get //Get all program users with experimental collaborator role List collabRoleUsers = programUserService.getProgramUsersByRole(programId, roleId); + List collaboratorResponses = new ArrayList<>(); - //let's start with case of finding users not assoc with experiment - //need new fancy model maybe - - Boolean isACollaborator = false; for (ProgramUser collabRoleUser : collabRoleUsers) { - //if collabRoleUser.getUser().getId(); - //should be something more efficient, right? - if (active){ - //return users with experimental collaborator role associated with this experiment - } else { - //return users with experimental collaborator role NOT associated with this experiment + UUID collaboratorId = null; + //check if user is an active collaborator for this experiment + Boolean isThisExpCollab = activeCollaboratorIds.contains(collabRoleUser.getId()); + + //If active, want to retrieve experimental collaborators added to the experiment + //If not active, want to retrieve experimental collaborators not added to the experiment + if ((active && isThisExpCollab) || (!active && !isThisExpCollab)) { + ExperimentalCollaboratorResponse collabResponse = new ExperimentalCollaboratorResponse(); + collabResponse.setActive(active); + collabResponse.setEmail(collabRoleUser.getUser().getEmail()); + collabResponse.setName(collabRoleUser.getUser().getName()); + collabResponse.setProgramUserId(collabRoleUser.getId()); + collabResponse.setCollaboratorId(collaboratorId); + collaboratorResponses.add(collabResponse); } } - //wait what *is* response type - //model ExperimentalCollaboratorResponse - - - //biuser has name and email - //program_user_role has id, user_id - - //experimentProgramUserRoleEntity with some stuff appended on - List metadataStatus = new ArrayList<>(); metadataStatus.add(new Status(StatusCode.INFO, "Successful Query")); //TODO: paging Pagination pagination = new Pagination(collaborators.size(), collaborators.size(), 1, 0); Metadata metadata = new Metadata(pagination, metadataStatus); - Response> response = new Response(metadata, new DataResponse<>(collaborators)); + //todo check response type + Response>> response = new Response(metadata, new DataResponse<>(collaboratorResponses)); return HttpResponse.ok(response); } catch (Exception e) { log.info(e.getMessage(), e); - HttpResponse response = HttpResponse.status(HttpStatus.INTERNAL_SERVER_ERROR, "todo").contentType(MediaType.TEXT_PLAIN).body("todo"); + HttpResponse response = HttpResponse.serverError(); return response; } - /* - -Response: -[ - { - "id": UUID, collaboratorId - "active": Boolean, - "userId": UUID,programUserId - "name": String, - "email": String - }, - { - "id": UUID, - "active": Boolean, - "userId": UUID, - "name": String, - "email": String - } -] - */ } From 1845cf25c62f29a0486faf0b3954c0ed085dd464 Mon Sep 17 00:00:00 2001 From: Nick <53413353+nickpalladino@users.noreply.github.com> Date: Wed, 21 Aug 2024 14:08:41 -0400 Subject: [PATCH 17/30] Added post and delete test --- .../ExperimentControllerIntegrationTest.java | 94 +++++++++++++++++-- 1 file changed, 87 insertions(+), 7 deletions(-) diff --git a/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java b/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java index 3d032b984..9b14e11a4 100644 --- a/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java +++ b/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java @@ -29,7 +29,11 @@ import org.breedinginsight.brapps.importer.model.exports.FileType; import org.breedinginsight.brapps.importer.model.imports.experimentObservation.ExperimentObservation; import org.breedinginsight.dao.db.enums.DataType; +import org.breedinginsight.dao.db.tables.daos.RoleDao; +import org.breedinginsight.dao.db.tables.pojos.ProgramUserRoleEntity; +import org.breedinginsight.dao.db.tables.pojos.RoleEntity; import org.breedinginsight.dao.db.tables.pojos.SpeciesEntity; +import org.breedinginsight.daos.ProgramUserDAO; import org.breedinginsight.daos.SpeciesDAO; import org.breedinginsight.daos.UserDAO; import org.breedinginsight.model.*; @@ -85,6 +89,10 @@ public class ExperimentControllerIntegrationTest extends BrAPITest { private BrAPITrialService experimentService; @Inject private BrAPIGermplasmDAO germplasmDAO; + @Inject + private ProgramUserDAO programUserDAO; + @Inject + private RoleDao roleDao; @Inject @Client("/${micronaut.bi.api.version}") @@ -358,10 +366,7 @@ void downloadSubEntityDataset(String extension) { /** * Tests for Experimental Collaborator endpoints * - * Create Experimental Collaborator - * - * Remove Experimental Collaborator - * + * TODO * * Get Experimental Collaborators Active * GIVEN GET /v1/programs/{programId}/experiments/{experimentId}/collaborators?active=true|false @@ -376,14 +381,13 @@ void downloadSubEntityDataset(String extension) { * WHEN program user has been added to experiment as collaborator * AND after being added as a collaborator, program user is deactivated from program * THEN response should be empty array regardless of active query parameter value (assumes single user) - * */ /** * Create Experimental Collaborator Invalid Id * GIVEN POST /v1/programs/{programId}/experiments/{experimentId}/collaborators * WHEN an invalid id is passed in the body of the request - * THEN response should be 422 (maybe should be bad request?) + * THEN response should be 404 */ @Test public void postExperimentalCollaboratorsInvalidId() { @@ -400,7 +404,83 @@ public void postExperimentalCollaboratorsInvalidId() { HttpResponse response = call.blockingFirst(); }); - assertEquals(HttpStatus.UNPROCESSABLE_ENTITY, e.getStatus()); + assertEquals(HttpStatus.NOT_FOUND, e.getStatus()); + } + + /** + * Create and Delete Experimental Collaborator + */ + @Test + public void postAndDeleteExperimentalCollaborator() { + + RoleEntity roleEntity = roleDao.fetchByDomain("Experimental Collaborator").get(0); + + ProgramUserRoleEntity programUserEntity = ProgramUserRoleEntity.builder() + .userId(otherTestUser.getId()) + .programId(program.getId()) + .roleId(roleEntity.getId()) + .createdBy(testUser.getId()) + .updatedBy(testUser.getId()) + .build(); + + programUserDAO.insert(programUserEntity); + + JsonObject requestBody = new JsonObject(); + requestBody.addProperty("userId", otherTestUser.getId().toString()); + + Flowable> call = client.exchange( + POST(String.format("/programs/%s/experiments/%s/collaborators", program.getId().toString(), experimentId), requestBody.toString()) + .contentType(MediaType.APPLICATION_JSON) + .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"); + String id = result.get("id").getAsString(); + Assertions.assertNotEquals(null, id); + + // check count = 1 + + call = client.exchange( + GET(String.format("/programs/%s/experiments/%s/collaborators?active=true", program.getId().toString(), experimentId)) + .contentType(MediaType.APPLICATION_JSON) + .cookie(new NettyCookie("phylo-token", "test-registered-user")), String.class + ); + response = call.blockingFirst(); + + assertEquals(HttpStatus.OK, response.getStatus()); + + result = JsonParser.parseString(response.body()).getAsJsonObject().getAsJsonObject("result"); + JsonArray data = result.getAsJsonArray("data"); + assertEquals(1, data.size()); + + // now delete + + call = client.exchange( + DELETE(String.format("/programs/%s/experiments/%s/collaborators/%s", program.getId().toString(), experimentId, id)) + .contentType(MediaType.APPLICATION_JSON) + .cookie(new NettyCookie("phylo-token", "test-registered-user")), String.class + ); + + response = call.blockingFirst(); + assertEquals(HttpStatus.OK, response.getStatus()); + + // check count = 0 + + call = client.exchange( + GET(String.format("/programs/%s/experiments/%s/collaborators?active=true", program.getId().toString(), experimentId)) + .contentType(MediaType.APPLICATION_JSON) + .cookie(new NettyCookie("phylo-token", "test-registered-user")), String.class + ); + response = call.blockingFirst(); + + assertEquals(HttpStatus.OK, response.getStatus()); + + result = JsonParser.parseString(response.body()).getAsJsonObject().getAsJsonObject("result"); + data = result.getAsJsonArray("data"); + assertEquals(0, data.size()); } /** From e9fb5fa7214b7263884bdb81107300002b3b3090 Mon Sep 17 00:00:00 2001 From: HMS17 Date: Wed, 21 Aug 2024 14:57:41 -0400 Subject: [PATCH 18/30] [BI-2256] - Switch to using userId, code to retrieve collabId --- .../v1/request/ExperimentCollaboratorRequest.java | 2 +- .../response/ExperimentalCollaboratorResponse.java | 2 ++ .../api/v1/controller/ExperimentController.java | 14 +++++++++----- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/breedinginsight/api/model/v1/request/ExperimentCollaboratorRequest.java b/src/main/java/org/breedinginsight/api/model/v1/request/ExperimentCollaboratorRequest.java index 85a1e43b9..b570be5f5 100644 --- a/src/main/java/org/breedinginsight/api/model/v1/request/ExperimentCollaboratorRequest.java +++ b/src/main/java/org/breedinginsight/api/model/v1/request/ExperimentCollaboratorRequest.java @@ -15,5 +15,5 @@ @Introspected public class ExperimentCollaboratorRequest { @NotBlank - private UUID programUserId; + private UUID userId; } diff --git a/src/main/java/org/breedinginsight/api/model/v1/response/ExperimentalCollaboratorResponse.java b/src/main/java/org/breedinginsight/api/model/v1/response/ExperimentalCollaboratorResponse.java index d9a308787..ce46cd4b3 100644 --- a/src/main/java/org/breedinginsight/api/model/v1/response/ExperimentalCollaboratorResponse.java +++ b/src/main/java/org/breedinginsight/api/model/v1/response/ExperimentalCollaboratorResponse.java @@ -40,6 +40,8 @@ public class ExperimentalCollaboratorResponse { private String name; @NotNull private String email; + @NotNull + private UUID userId; //todo determine notblank vs notnull } diff --git a/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java b/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java index 2cee30aef..a42fab0ed 100644 --- a/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java +++ b/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java @@ -170,7 +170,7 @@ public HttpResponse>> getDatasets( * Adds a record to the experiment_program_user_role table * @param programId The UUID of the program * @param experimentId The UUID of the experiment - * @param request ExperimentalCollaboratorRequest containing the UUID of the program user to add as a collaborator to the experiemnt + * @param request ExperimentalCollaboratorRequest containing the UUID of the bi user to add as a collaborator to the experiemnt * @return HttpResponse containing the newly created ExperimentProgramUserRoleEntity */ @Post("/${micronaut.bi.api.version}/programs/{programId}/experiments/{experimentId}/collaborators") @@ -189,15 +189,15 @@ public HttpResponse> createExperimenta } //Check if program user exists - Optional programUserOptional = programUserService.getProgramUserbyId(programId, request.getProgramUserId()); + Optional programUserOptional = programUserService.getProgramUserbyId(programId, request.getUserId()); if (programUserOptional.isEmpty()) { return HttpResponse.status(HttpStatus.NOT_FOUND, "Program user does not exist"); } - + //get active user creating the collaborator AuthenticatedUser createdByUser = securityService.getUser(); + UUID programUserId = programUserOptional.get().getId(); UUID createdByUserId = createdByUser.getId(); - UUID programUserId = request.getProgramUserId(); Response response = new Response(experimentalCollaboratorService.createExperimentalCollaborator(programUserId,experimentId,createdByUserId)); return HttpResponse.ok(response); } catch (Exception e){ @@ -244,6 +244,9 @@ public HttpResponse UUID collaboratorId = null; //check if user is an active collaborator for this experiment Boolean isThisExpCollab = activeCollaboratorIds.contains(collabRoleUser.getId()); + if (isThisExpCollab) { + collaboratorId = collaborators.get(activeCollaboratorIds.indexOf(collabRoleUser.getId())).getId(); //todo may implement in cleaner manner + } //If active, want to retrieve experimental collaborators added to the experiment //If not active, want to retrieve experimental collaborators not added to the experiment @@ -252,7 +255,8 @@ public HttpResponse collabResponse.setActive(active); collabResponse.setEmail(collabRoleUser.getUser().getEmail()); collabResponse.setName(collabRoleUser.getUser().getName()); - collabResponse.setProgramUserId(collabRoleUser.getId()); + collabResponse.setProgramUserId(collabRoleUser.getId()); //todo see if this can be fully removed + collabResponse.setUserId(collabRoleUser.getUserId()); collabResponse.setCollaboratorId(collaboratorId); collaboratorResponses.add(collabResponse); } From 5f7d9e23128df12bee46c5bf50572c4ba064c306 Mon Sep 17 00:00:00 2001 From: Nick <53413353+nickpalladino@users.noreply.github.com> Date: Wed, 21 Aug 2024 16:06:39 -0400 Subject: [PATCH 19/30] Added another get test --- .../ExperimentControllerIntegrationTest.java | 83 ++++++++++++++++--- ...amSecuredAnnotationRuleIntegrationTest.sql | 6 ++ 2 files changed, 78 insertions(+), 11 deletions(-) diff --git a/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java b/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java index 9b14e11a4..e891cf775 100644 --- a/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java +++ b/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java @@ -368,14 +368,6 @@ void downloadSubEntityDataset(String extension) { * * TODO * - * Get Experimental Collaborators Active - * GIVEN GET /v1/programs/{programId}/experiments/{experimentId}/collaborators?active=true|false - * WHEN program user has been added to experiment as collaborator - * AND program user with Experimental Collaborator role exists in program - * THEN response should be: - * array with program user when active=true - * empty array when active=false - * * Get Experimental Collaborators Deactivated from Program * GIVEN GET /v1/programs/{programId}/experiments/{experimentId}/collaborators?active=true|false * WHEN program user has been added to experiment as collaborator @@ -442,7 +434,6 @@ public void postAndDeleteExperimentalCollaborator() { Assertions.assertNotEquals(null, id); // check count = 1 - call = client.exchange( GET(String.format("/programs/%s/experiments/%s/collaborators?active=true", program.getId().toString(), experimentId)) .contentType(MediaType.APPLICATION_JSON) @@ -457,7 +448,6 @@ public void postAndDeleteExperimentalCollaborator() { assertEquals(1, data.size()); // now delete - call = client.exchange( DELETE(String.format("/programs/%s/experiments/%s/collaborators/%s", program.getId().toString(), experimentId, id)) .contentType(MediaType.APPLICATION_JSON) @@ -468,7 +458,6 @@ public void postAndDeleteExperimentalCollaborator() { assertEquals(HttpStatus.OK, response.getStatus()); // check count = 0 - call = client.exchange( GET(String.format("/programs/%s/experiments/%s/collaborators?active=true", program.getId().toString(), experimentId)) .contentType(MediaType.APPLICATION_JSON) @@ -481,6 +470,10 @@ public void postAndDeleteExperimentalCollaborator() { result = JsonParser.parseString(response.body()).getAsJsonObject().getAsJsonObject("result"); data = result.getAsJsonArray("data"); assertEquals(0, data.size()); + + // clean up + programUserDAO.deleteProgramUserRoles(program.getId(), otherTestUser.getId()); + } /** @@ -553,6 +546,74 @@ public void getExperimentalCollaboratorsNoActive(boolean active) { } + /** + * Get Experimental Collaborators Active + * GIVEN GET /v1/programs/{programId}/experiments/{experimentId}/collaborators?active=true|false + * WHEN program user has been added to experiment as collaborator + * AND program user with Experimental Collaborator role exists in program + * THEN response should be: + * array with program user when active=true + * empty array when active=false + */ + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void getExperimentalCollaboratorsActive(boolean active) { + // add a program user with the experimental collaborator role + FannyPack securityFp = FannyPack.fill("src/test/resources/sql/ProgramSecuredAnnotationRuleIntegrationTest.sql"); + dsl.execute(securityFp.get("InsertProgramRolesExperimentalCollaborator"), otherTestUser.getId().toString(), program.getId()); + + // add user as experimental collaborator + JsonObject requestBody = new JsonObject(); + requestBody.addProperty("userId", otherTestUser.getId().toString()); + + Flowable> call = client.exchange( + POST(String.format("/programs/%s/experiments/%s/collaborators", program.getId().toString(), experimentId), requestBody.toString()) + .contentType(MediaType.APPLICATION_JSON) + .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"); + String id = result.get("id").getAsString(); + Assertions.assertNotEquals(null, id); + + // get experimental collaborators + call = client.exchange( + GET(String.format("/programs/%s/experiments/%s/collaborators?active=%s", program.getId().toString(), experimentId, active)) + .contentType(MediaType.APPLICATION_JSON) + .cookie(new NettyCookie("phylo-token", "test-registered-user")), String.class + ); + response = call.blockingFirst(); + + assertEquals(HttpStatus.OK, response.getStatus()); + + result = JsonParser.parseString(response.body()).getAsJsonObject().getAsJsonObject("result"); + JsonArray data = result.getAsJsonArray("data"); + + if (active) { + assertEquals(1, data.size()); + } else { + assertEquals(0, data.size()); + // TODO: check user details + } + + // cleanup - delete collaborator + call = client.exchange( + DELETE(String.format("/programs/%s/experiments/%s/collaborators/%s", program.getId().toString(), experimentId, id)) + .contentType(MediaType.APPLICATION_JSON) + .cookie(new NettyCookie("phylo-token", "test-registered-user")), String.class + ); + + response = call.blockingFirst(); + assertEquals(HttpStatus.OK, response.getStatus()); + + // delete program user from setup + // NOTE: if test fails this may not be run and could impact other tests results + dsl.execute(securityFp.get("DeleteProgramUser"), otherTestUser.getId().toString()); + } + private List> buildSubEntityRows(List> topLevelRows, String entityName, int repeatedMeasures) { List> plantRows = new ArrayList<>(); for (Map row : topLevelRows) { diff --git a/src/test/resources/sql/ProgramSecuredAnnotationRuleIntegrationTest.sql b/src/test/resources/sql/ProgramSecuredAnnotationRuleIntegrationTest.sql index dc4e40e49..7bd85d9be 100644 --- a/src/test/resources/sql/ProgramSecuredAnnotationRuleIntegrationTest.sql +++ b/src/test/resources/sql/ProgramSecuredAnnotationRuleIntegrationTest.sql @@ -70,6 +70,12 @@ DELETE FROM program_user_role WHERE program_user_role.role_id = role.id AND role.domain = 'Experimental Collaborator'; +-- name: DeleteExperimentalCollaborator + +DELETE FROM experiment_program_user_role +WHERE id = :id:uuid; + + -- name: DeleteProgramUser DELETE FROM program_user_role From a138f572116576009430b72f71e082d0eca692d6 Mon Sep 17 00:00:00 2001 From: Nick <53413353+nickpalladino@users.noreply.github.com> Date: Wed, 21 Aug 2024 17:05:27 -0400 Subject: [PATCH 20/30] Added get after deactivated test --- .../ExperimentControllerIntegrationTest.java | 84 +++++++++++++++++-- 1 file changed, 76 insertions(+), 8 deletions(-) diff --git a/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java b/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java index e891cf775..a48318828 100644 --- a/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java +++ b/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java @@ -6,6 +6,7 @@ import io.micronaut.http.HttpResponse; import io.micronaut.http.HttpStatus; import io.micronaut.http.MediaType; +import io.micronaut.http.annotation.Delete; import io.micronaut.http.client.RxHttpClient; import io.micronaut.http.client.annotation.Client; import io.micronaut.http.client.exceptions.HttpClientResponseException; @@ -365,14 +366,6 @@ void downloadSubEntityDataset(String extension) { /** * Tests for Experimental Collaborator endpoints - * - * TODO - * - * Get Experimental Collaborators Deactivated from Program - * GIVEN GET /v1/programs/{programId}/experiments/{experimentId}/collaborators?active=true|false - * WHEN program user has been added to experiment as collaborator - * AND after being added as a collaborator, program user is deactivated from program - * THEN response should be empty array regardless of active query parameter value (assumes single user) */ /** @@ -614,6 +607,81 @@ public void getExperimentalCollaboratorsActive(boolean active) { dsl.execute(securityFp.get("DeleteProgramUser"), otherTestUser.getId().toString()); } + /** + * Get Experimental Collaborators Deactivated from Program + * GIVEN GET /v1/programs/{programId}/experiments/{experimentId}/collaborators?active=true|false + * WHEN program user has been added to experiment as collaborator + * AND after being added as a collaborator, program user is deactivated from program + * THEN response should be empty array regardless of active query parameter value (assumes single user) + */ + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void getExperimentalCollaboratorsDeactivated(boolean active) { + // add a program user with the experimental collaborator role + FannyPack securityFp = FannyPack.fill("src/test/resources/sql/ProgramSecuredAnnotationRuleIntegrationTest.sql"); + dsl.execute(securityFp.get("InsertProgramRolesExperimentalCollaborator"), otherTestUser.getId().toString(), program.getId()); + + // add user as experimental collaborator + JsonObject requestBody = new JsonObject(); + requestBody.addProperty("userId", otherTestUser.getId().toString()); + + Flowable> call = client.exchange( + POST(String.format("/programs/%s/experiments/%s/collaborators", program.getId().toString(), experimentId), requestBody.toString()) + .contentType(MediaType.APPLICATION_JSON) + .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"); + String id = result.get("id").getAsString(); + Assertions.assertNotEquals(null, id); + + // deactivate program user + call = client.exchange( + DELETE(String.format("/programs/%s/users/%s", program.getId().toString(), otherTestUser.getId().toString())) + .contentType(MediaType.APPLICATION_JSON) + .cookie(new NettyCookie("phylo-token", "test-registered-user")), String.class + ); + + response = call.blockingFirst(); + assertEquals(HttpStatus.OK, response.getStatus()); + + // get experimental collaborators + call = client.exchange( + GET(String.format("/programs/%s/experiments/%s/collaborators?active=%s", program.getId().toString(), experimentId, active)) + .contentType(MediaType.APPLICATION_JSON) + .cookie(new NettyCookie("phylo-token", "test-registered-user")), String.class + ); + response = call.blockingFirst(); + + assertEquals(HttpStatus.OK, response.getStatus()); + + result = JsonParser.parseString(response.body()).getAsJsonObject().getAsJsonObject("result"); + JsonArray data = result.getAsJsonArray("data"); + + if (active) { + assertEquals(0, data.size()); + } else { + assertEquals(0, data.size()); + } + + // cleanup - remove collaborator + call = client.exchange( + DELETE(String.format("/programs/%s/experiments/%s/collaborators/%s", program.getId().toString(), experimentId, id)) + .contentType(MediaType.APPLICATION_JSON) + .cookie(new NettyCookie("phylo-token", "test-registered-user")), String.class + ); + + response = call.blockingFirst(); + assertEquals(HttpStatus.OK, response.getStatus()); + + // delete program user from setup + // NOTE: if test fails this may not be run and could impact other tests results + dsl.execute(securityFp.get("DeleteProgramUser"), otherTestUser.getId().toString()); + } + + private List> buildSubEntityRows(List> topLevelRows, String entityName, int repeatedMeasures) { List> plantRows = new ArrayList<>(); for (Map row : topLevelRows) { From 05284ccfe06fe1ff20c5b3115773ff55b1361e86 Mon Sep 17 00:00:00 2001 From: Nick <53413353+nickpalladino@users.noreply.github.com> Date: Wed, 21 Aug 2024 17:08:54 -0400 Subject: [PATCH 21/30] Simplified test --- .../brapi/v2/ExperimentControllerIntegrationTest.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java b/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java index a48318828..e57533050 100644 --- a/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java +++ b/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java @@ -660,11 +660,8 @@ public void getExperimentalCollaboratorsDeactivated(boolean active) { result = JsonParser.parseString(response.body()).getAsJsonObject().getAsJsonObject("result"); JsonArray data = result.getAsJsonArray("data"); - if (active) { - assertEquals(0, data.size()); - } else { - assertEquals(0, data.size()); - } + // should be empty regardless of active query parameter value + assertEquals(0, data.size()); // cleanup - remove collaborator call = client.exchange( From 7061ed5ce995940b1d42d4e8ebfd83337f7eeb14 Mon Sep 17 00:00:00 2001 From: Nick <53413353+nickpalladino@users.noreply.github.com> Date: Wed, 21 Aug 2024 17:10:29 -0400 Subject: [PATCH 22/30] Removed comment --- .../brapi/v2/ExperimentControllerIntegrationTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java b/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java index e57533050..64c69ed20 100644 --- a/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java +++ b/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java @@ -589,7 +589,6 @@ public void getExperimentalCollaboratorsActive(boolean active) { assertEquals(1, data.size()); } else { assertEquals(0, data.size()); - // TODO: check user details } // cleanup - delete collaborator From 6f9541f3f3cef62990adbac169be76cd19dd334f Mon Sep 17 00:00:00 2001 From: Nick <53413353+nickpalladino@users.noreply.github.com> Date: Thu, 22 Aug 2024 10:04:22 -0400 Subject: [PATCH 23/30] Added response checks for active=false case --- .../brapi/v2/ExperimentControllerIntegrationTest.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java b/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java index 64c69ed20..bd514dc34 100644 --- a/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java +++ b/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java @@ -513,6 +513,8 @@ public void getExperimentalCollaboratorsNoActive(boolean active) { FannyPack securityFp = FannyPack.fill("src/test/resources/sql/ProgramSecuredAnnotationRuleIntegrationTest.sql"); dsl.execute(securityFp.get("InsertProgramRolesExperimentalCollaborator"), otherTestUser.getId().toString(), program.getId()); + ProgramUser programUser = programUserDAO.getProgramUser(program.getId(), otherTestUser.getId()); + Flowable> call = client.exchange( GET(String.format("/programs/%s/experiments/%s/collaborators?active=%s", program.getId().toString(), experimentId, active)) .contentType(MediaType.APPLICATION_JSON) @@ -530,7 +532,14 @@ public void getExperimentalCollaboratorsNoActive(boolean active) { } else { assertEquals(1, data.size()); // TODO: check user details - + JsonObject collaborator = data.get(0).getAsJsonObject(); + // Currently not returning key rather than key with null + //assertEquals(collaborator.get("collaboratorId").getAsString(),null, "Expected null for id"); + assertEquals(collaborator.get("userId").getAsString(), otherTestUser.getId().toString(), "Unexpected userId"); + assertEquals(collaborator.get("programUserId").getAsString(), programUser.getId().toString(), "Unexpected programUserId"); + assertEquals(collaborator.get("name").getAsString(), otherTestUser.getName(), "Unexpected name"); + assertEquals(collaborator.get("email").getAsString(), otherTestUser.getEmail(), "Unexpected email"); + assertEquals(collaborator.get("active").getAsBoolean(), false, "Unexpected active status"); } // delete program user from setup From 5c050c4ab6447ab6308584a846283ec1ebe6ee71 Mon Sep 17 00:00:00 2001 From: Nick <53413353+nickpalladino@users.noreply.github.com> Date: Thu, 22 Aug 2024 10:10:10 -0400 Subject: [PATCH 24/30] Added response checks for active=true case --- .../brapi/v2/ExperimentControllerIntegrationTest.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java b/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java index bd514dc34..0d3ed574f 100644 --- a/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java +++ b/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java @@ -409,6 +409,7 @@ public void postAndDeleteExperimentalCollaborator() { .build(); programUserDAO.insert(programUserEntity); + ProgramUser programUser = programUserDAO.getProgramUser(program.getId(), otherTestUser.getId()); JsonObject requestBody = new JsonObject(); requestBody.addProperty("userId", otherTestUser.getId().toString()); @@ -439,6 +440,14 @@ public void postAndDeleteExperimentalCollaborator() { result = JsonParser.parseString(response.body()).getAsJsonObject().getAsJsonObject("result"); JsonArray data = result.getAsJsonArray("data"); assertEquals(1, data.size()); + JsonObject collaborator = data.get(0).getAsJsonObject(); + + assertNotEquals(collaborator.get("collaboratorId").getAsString(),null, "Expected not null for collaboratorId"); + assertEquals(collaborator.get("userId").getAsString(), otherTestUser.getId().toString(), "Unexpected userId"); + assertEquals(collaborator.get("programUserId").getAsString(), programUser.getId().toString(), "Unexpected programUserId"); + assertEquals(collaborator.get("name").getAsString(), otherTestUser.getName(), "Unexpected name"); + assertEquals(collaborator.get("email").getAsString(), otherTestUser.getEmail(), "Unexpected email"); + assertEquals(collaborator.get("active").getAsBoolean(), true, "Unexpected active status"); // now delete call = client.exchange( @@ -531,7 +540,6 @@ public void getExperimentalCollaboratorsNoActive(boolean active) { assertEquals(0, data.size()); } else { assertEquals(1, data.size()); - // TODO: check user details JsonObject collaborator = data.get(0).getAsJsonObject(); // Currently not returning key rather than key with null //assertEquals(collaborator.get("collaboratorId").getAsString(),null, "Expected null for id"); From 49a412726d0bb0173a6803fa0ec644f91d335374 Mon Sep 17 00:00:00 2001 From: HMS17 Date: Thu, 22 Aug 2024 12:58:25 -0400 Subject: [PATCH 25/30] [BI-2256] - Cleanup --- .../v1/response/ExperimentalCollaboratorResponse.java | 11 ++++------- .../api/v1/controller/ExperimentController.java | 9 +-------- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/src/main/java/org/breedinginsight/api/model/v1/response/ExperimentalCollaboratorResponse.java b/src/main/java/org/breedinginsight/api/model/v1/response/ExperimentalCollaboratorResponse.java index ce46cd4b3..1ff082537 100644 --- a/src/main/java/org/breedinginsight/api/model/v1/response/ExperimentalCollaboratorResponse.java +++ b/src/main/java/org/breedinginsight/api/model/v1/response/ExperimentalCollaboratorResponse.java @@ -20,6 +20,7 @@ import lombok.*; import lombok.experimental.Accessors; +import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; import java.util.UUID; @@ -34,14 +35,10 @@ public class ExperimentalCollaboratorResponse { private UUID collaboratorId; @NotNull private Boolean active; - @NotNull - private UUID programUserId; - @NotNull + @NotBlank private String name; - @NotNull + @NotBlank private String email; - @NotNull + @NotBlank private UUID userId; - //todo determine notblank vs notnull - } diff --git a/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java b/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java index 9d34f944f..338a3e14c 100644 --- a/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java +++ b/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java @@ -226,11 +226,7 @@ public HttpResponse @PathVariable("experimentId") UUID experimentId, @QueryValue(defaultValue = "true") Boolean active ) { - //todo confirm what default of active should be/if there should be a default - try { - //Program program = programService.getById(programId).orElseThrow(() -> new DoesNotExistException("Program does not exist")); - //Get experimental collaborators associated with the experiment List collaborators = experimentalCollaboratorService.getExperimentalCollaborators(experimentId); List activeCollaboratorIds = collaborators.stream().map((ExperimentProgramUserRoleEntity::getProgramUserRoleId)).collect(Collectors.toList()); @@ -248,7 +244,7 @@ public HttpResponse //check if user is an active collaborator for this experiment Boolean isThisExpCollab = activeCollaboratorIds.contains(collabRoleUser.getId()); if (isThisExpCollab) { - collaboratorId = collaborators.get(activeCollaboratorIds.indexOf(collabRoleUser.getId())).getId(); //todo may implement in cleaner manner + collaboratorId = collaborators.get(activeCollaboratorIds.indexOf(collabRoleUser.getId())).getId(); } //If active, want to retrieve experimental collaborators added to the experiment @@ -258,7 +254,6 @@ public HttpResponse collabResponse.setActive(active); collabResponse.setEmail(collabRoleUser.getUser().getEmail()); collabResponse.setName(collabRoleUser.getUser().getName()); - collabResponse.setProgramUserId(collabRoleUser.getId()); //todo see if this can be fully removed collabResponse.setUserId(collabRoleUser.getUserId()); collabResponse.setCollaboratorId(collaboratorId); collaboratorResponses.add(collabResponse); @@ -271,7 +266,6 @@ public HttpResponse Pagination pagination = new Pagination(collaborators.size(), collaborators.size(), 1, 0); Metadata metadata = new Metadata(pagination, metadataStatus); - //todo check response type Response>> response = new Response(metadata, new DataResponse<>(collaboratorResponses)); return HttpResponse.ok(response); } catch (Exception e) { @@ -298,7 +292,6 @@ public HttpResponse deleteExperimentalCollaborator( @PathVariable("collaboratorId") UUID collaboratorId ) { try { - //todo double check this endpoint would be getting the collaboratorId and not the programUserRoleId experimentalCollaboratorService.deleteExperimentalCollaborator(collaboratorId); return HttpResponse.ok(); } catch (Exception e) { From f3beeb0bf88cac2c8f0a34aaeedeb8229a73d1e4 Mon Sep 17 00:00:00 2001 From: HMS17 Date: Thu, 22 Aug 2024 14:01:21 -0400 Subject: [PATCH 26/30] [BI-2256] - Cleanup and fixing unit test --- .../model/v1/response/ExperimentalCollaboratorResponse.java | 4 +++- .../api/v1/controller/ExperimentController.java | 5 +++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/breedinginsight/api/model/v1/response/ExperimentalCollaboratorResponse.java b/src/main/java/org/breedinginsight/api/model/v1/response/ExperimentalCollaboratorResponse.java index 1ff082537..5ae65b050 100644 --- a/src/main/java/org/breedinginsight/api/model/v1/response/ExperimentalCollaboratorResponse.java +++ b/src/main/java/org/breedinginsight/api/model/v1/response/ExperimentalCollaboratorResponse.java @@ -31,7 +31,7 @@ @NoArgsConstructor @AllArgsConstructor public class ExperimentalCollaboratorResponse { - //is null in case where active=false + //collaboratorId is null in case where active=false private UUID collaboratorId; @NotNull private Boolean active; @@ -41,4 +41,6 @@ public class ExperimentalCollaboratorResponse { private String email; @NotBlank private UUID userId; + @NotBlank + private UUID programUserId; } diff --git a/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java b/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java index 338a3e14c..9e8ef7cfc 100644 --- a/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java +++ b/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java @@ -149,7 +149,7 @@ public HttpResponse> createSubEntityDataset( * @param experimentId The UUID of the experiment. * @return An HttpResponse with a Response object containing a list of DatasetMetadata. * @throws DoesNotExistException if the program does not exist. - * @throws ApiException if an error occurs while retrieving the datasets.UserId + * @throws ApiException if an error occurs while retrieving the datasets */ @Get("/${micronaut.bi.api.version}/programs/{programId}/experiments/{experimentId}/datasets") @ExperimentCollaboratorSecured @@ -215,7 +215,7 @@ public HttpResponse> createExperimenta * @param programId The UUID of the program * @param experimentId The UUID of the experiment * @param active true if querying for collaborators added as a collaborator to the experiment, false if querying for collaborators not added - * @return + * @return list of ExperimentalCollaboratorResponse * Response includes name and email as a convenience to the front end to avoid making another api call */ @Get("/${micronaut.bi.api.version}/programs/{programId}/experiments/{experimentId}/collaborators{?active}") @@ -255,6 +255,7 @@ public HttpResponse collabResponse.setEmail(collabRoleUser.getUser().getEmail()); collabResponse.setName(collabRoleUser.getUser().getName()); collabResponse.setUserId(collabRoleUser.getUserId()); + collabResponse.setProgramUserId(collabRoleUser.getId()); collabResponse.setCollaboratorId(collaboratorId); collaboratorResponses.add(collabResponse); } From b7d03f2996c8eaf1f986285a384ef86550bf2b5f Mon Sep 17 00:00:00 2001 From: HMS17 Date: Thu, 22 Aug 2024 14:25:42 -0400 Subject: [PATCH 27/30] [BI-2256] - Removing unused programUserId in response --- .../model/v1/response/ExperimentalCollaboratorResponse.java | 2 -- .../api/v1/controller/ExperimentController.java | 1 - .../brapi/v2/ExperimentControllerIntegrationTest.java | 6 ++---- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/breedinginsight/api/model/v1/response/ExperimentalCollaboratorResponse.java b/src/main/java/org/breedinginsight/api/model/v1/response/ExperimentalCollaboratorResponse.java index 5ae65b050..dc0bfc5c2 100644 --- a/src/main/java/org/breedinginsight/api/model/v1/response/ExperimentalCollaboratorResponse.java +++ b/src/main/java/org/breedinginsight/api/model/v1/response/ExperimentalCollaboratorResponse.java @@ -41,6 +41,4 @@ public class ExperimentalCollaboratorResponse { private String email; @NotBlank private UUID userId; - @NotBlank - private UUID programUserId; } diff --git a/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java b/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java index 9e8ef7cfc..46c32a871 100644 --- a/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java +++ b/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java @@ -255,7 +255,6 @@ public HttpResponse collabResponse.setEmail(collabRoleUser.getUser().getEmail()); collabResponse.setName(collabRoleUser.getUser().getName()); collabResponse.setUserId(collabRoleUser.getUserId()); - collabResponse.setProgramUserId(collabRoleUser.getId()); collabResponse.setCollaboratorId(collaboratorId); collaboratorResponses.add(collabResponse); } diff --git a/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java b/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java index 0d3ed574f..55ae8853a 100644 --- a/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java +++ b/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java @@ -444,7 +444,6 @@ public void postAndDeleteExperimentalCollaborator() { assertNotEquals(collaborator.get("collaboratorId").getAsString(),null, "Expected not null for collaboratorId"); assertEquals(collaborator.get("userId").getAsString(), otherTestUser.getId().toString(), "Unexpected userId"); - assertEquals(collaborator.get("programUserId").getAsString(), programUser.getId().toString(), "Unexpected programUserId"); assertEquals(collaborator.get("name").getAsString(), otherTestUser.getName(), "Unexpected name"); assertEquals(collaborator.get("email").getAsString(), otherTestUser.getEmail(), "Unexpected email"); assertEquals(collaborator.get("active").getAsBoolean(), true, "Unexpected active status"); @@ -541,10 +540,9 @@ public void getExperimentalCollaboratorsNoActive(boolean active) { } else { assertEquals(1, data.size()); JsonObject collaborator = data.get(0).getAsJsonObject(); - // Currently not returning key rather than key with null - //assertEquals(collaborator.get("collaboratorId").getAsString(),null, "Expected null for id"); + // Currently not returning key rather than key with null todo check + assertEquals(collaborator.get("collaboratorId").getAsString(),null, "Expected null for id"); assertEquals(collaborator.get("userId").getAsString(), otherTestUser.getId().toString(), "Unexpected userId"); - assertEquals(collaborator.get("programUserId").getAsString(), programUser.getId().toString(), "Unexpected programUserId"); assertEquals(collaborator.get("name").getAsString(), otherTestUser.getName(), "Unexpected name"); assertEquals(collaborator.get("email").getAsString(), otherTestUser.getEmail(), "Unexpected email"); assertEquals(collaborator.get("active").getAsBoolean(), false, "Unexpected active status"); From 06aa11d8c439d1bdd803a5b76e75d72273da512a Mon Sep 17 00:00:00 2001 From: HMS17 Date: Thu, 22 Aug 2024 15:07:40 -0400 Subject: [PATCH 28/30] [BI-2256] - unit test --- .../brapi/v2/ExperimentControllerIntegrationTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java b/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java index 55ae8853a..afc17bda7 100644 --- a/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java +++ b/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java @@ -541,7 +541,8 @@ public void getExperimentalCollaboratorsNoActive(boolean active) { assertEquals(1, data.size()); JsonObject collaborator = data.get(0).getAsJsonObject(); // Currently not returning key rather than key with null todo check - assertEquals(collaborator.get("collaboratorId").getAsString(),null, "Expected null for id"); + assertNull(collaborator.get("collaboratorId"), "Expected null for id"); + //assertEquals(collaborator.get("collaboratorId").getAsString(),null, "Expected null for id"); assertEquals(collaborator.get("userId").getAsString(), otherTestUser.getId().toString(), "Unexpected userId"); assertEquals(collaborator.get("name").getAsString(), otherTestUser.getName(), "Unexpected name"); assertEquals(collaborator.get("email").getAsString(), otherTestUser.getEmail(), "Unexpected email"); From 22546034e3d24187c2ef3a41d81d562281bd63a8 Mon Sep 17 00:00:00 2001 From: HMS17 Date: Thu, 22 Aug 2024 15:24:18 -0400 Subject: [PATCH 29/30] [BI-2256] - unit test --- .../brapi/v2/ExperimentControllerIntegrationTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java b/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java index afc17bda7..2e4153ee8 100644 --- a/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java +++ b/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java @@ -540,9 +540,7 @@ public void getExperimentalCollaboratorsNoActive(boolean active) { } else { assertEquals(1, data.size()); JsonObject collaborator = data.get(0).getAsJsonObject(); - // Currently not returning key rather than key with null todo check assertNull(collaborator.get("collaboratorId"), "Expected null for id"); - //assertEquals(collaborator.get("collaboratorId").getAsString(),null, "Expected null for id"); assertEquals(collaborator.get("userId").getAsString(), otherTestUser.getId().toString(), "Unexpected userId"); assertEquals(collaborator.get("name").getAsString(), otherTestUser.getName(), "Unexpected name"); assertEquals(collaborator.get("email").getAsString(), otherTestUser.getEmail(), "Unexpected email"); From ad3c5cbc103d1b85cfe158fedece711bc1a8cfac Mon Sep 17 00:00:00 2001 From: HMS17 Date: Tue, 27 Aug 2024 14:46:21 -0400 Subject: [PATCH 30/30] [BI-2256] - moved tests --- .../v1/controller}/ExperimentControllerIntegrationTest.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) rename src/test/java/org/breedinginsight/{brapi/v2 => api/v1/controller}/ExperimentControllerIntegrationTest.java (99%) diff --git a/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java b/src/test/java/org/breedinginsight/api/v1/controller/ExperimentControllerIntegrationTest.java similarity index 99% rename from src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java rename to src/test/java/org/breedinginsight/api/v1/controller/ExperimentControllerIntegrationTest.java index 2e4153ee8..cdde3ef14 100644 --- a/src/test/java/org/breedinginsight/brapi/v2/ExperimentControllerIntegrationTest.java +++ b/src/test/java/org/breedinginsight/api/v1/controller/ExperimentControllerIntegrationTest.java @@ -1,4 +1,4 @@ -package org.breedinginsight.brapi.v2; +package org.breedinginsight.api.v1.controller; import com.google.gson.*; import io.kowalski.fannypack.FannyPack; @@ -6,7 +6,6 @@ import io.micronaut.http.HttpResponse; import io.micronaut.http.HttpStatus; import io.micronaut.http.MediaType; -import io.micronaut.http.annotation.Delete; import io.micronaut.http.client.RxHttpClient; import io.micronaut.http.client.annotation.Client; import io.micronaut.http.client.exceptions.HttpClientResponseException; @@ -23,7 +22,6 @@ import org.breedinginsight.api.auth.AuthenticatedUser; import org.breedinginsight.api.model.v1.request.ProgramRequest; import org.breedinginsight.api.model.v1.request.SpeciesRequest; -import org.breedinginsight.api.v1.controller.TestTokenValidator; import org.breedinginsight.brapi.v2.dao.BrAPIGermplasmDAO; import org.breedinginsight.brapi.v2.services.BrAPITrialService; import org.breedinginsight.brapps.importer.ImportTestUtils;