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 c846fb17d..988402889 100644 --- a/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java +++ b/src/main/java/org/breedinginsight/api/v1/controller/ExperimentController.java @@ -122,7 +122,7 @@ public HttpResponse> getDatasetData( * @return An HttpResponse with a Response object containing the newly created Dataset. */ @Post("/${micronaut.bi.api.version}/programs/{programId}/experiments/{experimentId}/dataset") - @ProgramSecured(roleGroups = {ProgramSecuredRoleGroup.PROGRAM_SCOPED_ROLES}) + @ProgramSecured(roles = {ProgramSecuredRole.PROGRAM_ADMIN}) @Produces(MediaType.APPLICATION_JSON) public HttpResponse> createSubEntityDataset( @PathVariable("programId") UUID programId, diff --git a/src/test/java/org/breedinginsight/api/v1/controller/ExperimentControllerIntegrationTest.java b/src/test/java/org/breedinginsight/api/v1/controller/ExperimentControllerIntegrationTest.java index 7c5c2a872..506c89cef 100644 --- a/src/test/java/org/breedinginsight/api/v1/controller/ExperimentControllerIntegrationTest.java +++ b/src/test/java/org/breedinginsight/api/v1/controller/ExperimentControllerIntegrationTest.java @@ -10,7 +10,7 @@ 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.micronaut.test.extensions.junit5.annotation.MicronautTest; import io.reactivex.Flowable; import lombok.SneakyThrows; import org.apache.commons.io.FileUtils; @@ -464,6 +464,54 @@ public void createSubEntityDatasetAllowsExpUnitNameUsedInOtherExperiment() throw assertEquals(HttpStatus.OK, response.getStatus()); } + @Test + public void createSubEntityDatasetForbiddenForExperimentalCollaborator() throws Exception { + // add otherTestUser to the program as an Experimental Collaborator + FannyPack securityFp = FannyPack.fill("src/test/resources/sql/ProgramSecuredAnnotationRuleIntegrationTest.sql"); + dsl.execute(securityFp.get("InsertProgramRolesExperimentalCollaborator"), otherTestUser.getId().toString(), program.getId()); + + // add that user to this experiment as a collaborator + JsonObject requestBody = new JsonObject(); + requestBody.addProperty("userId", otherTestUser.getId().toString()); + + Flowable> collaboratorCall = 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 collaboratorResponse = collaboratorCall.blockingFirst(); + assertEquals(HttpStatus.OK, collaboratorResponse.getStatus()); + + JsonObject collaboratorResult = JsonParser.parseString(collaboratorResponse.body()).getAsJsonObject().getAsJsonObject("result"); + String collaboratorId = collaboratorResult.get("id").getAsString(); + + // collaborator should be blocked from creating sub-entity datasets directly + Flowable> call = client.exchange( + POST(String.format("/programs/%s/experiments/%s/dataset", program.getId(), experimentId), + "{\"name\":\"Plant\",\"repeatedMeasures\":2}") + .contentType(MediaType.APPLICATION_JSON) + .cookie(new NettyCookie("phylo-token", "other-registered-user")), + String.class + ); + + HttpClientResponseException e = assertThrows(HttpClientResponseException.class, call::blockingFirst); + assertEquals(HttpStatus.FORBIDDEN, e.getStatus()); + + // cleanup collaborator record + Flowable> deleteCall = client.exchange( + DELETE(String.format("/programs/%s/experiments/%s/collaborators/%s", program.getId().toString(), experimentId, collaboratorId)) + .contentType(MediaType.APPLICATION_JSON) + .cookie(new NettyCookie("phylo-token", "test-registered-user")), + String.class + ); + HttpResponse deleteResponse = deleteCall.blockingFirst(); + assertEquals(HttpStatus.OK, deleteResponse.getStatus()); + + // cleanup program user role + dsl.execute(securityFp.get("DeleteProgramUser"), otherTestUser.getId().toString()); + } + @Test public void recommendedSubEntityDatasetNamesIncludeExpUnitNamesFromOtherExperiments() throws Exception { Program testProgram = createSeededProgram("Recommended Names");