Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
c276114
[BI-2256] - Experimental Collaborator BI-API Changes
HMS17 Aug 15, 2024
5a15024
Added first GET collaborators test and updated controller method
nickpalladino Aug 15, 2024
2a9b748
[BI-2256] - Small refactoring, endpoint progress
HMS17 Aug 16, 2024
4b5f9b4
[BI-2256] - Working on GET, RoleService helper method
HMS17 Aug 16, 2024
c8763fe
Added second GET test and some user setup and teardown
nickpalladino Aug 19, 2024
6f24db7
Delete src/main/java/org/breedinginsight/utilities/out.csv
nickpalladino Aug 19, 2024
65cbbde
Added test for POST with invalid program user id and updated request …
nickpalladino Aug 19, 2024
feb6258
[BI-2256] - GET method, some other fixes
HMS17 Aug 20, 2024
29b28ac
[BI-2256] - Experimental Collaborator BI-API Changes
HMS17 Aug 15, 2024
ef7dd26
Added first GET collaborators test and updated controller method
nickpalladino Aug 15, 2024
90b976d
[BI-2256] - Small refactoring, endpoint progress
HMS17 Aug 16, 2024
3ad6c1b
[BI-2256] - Working on GET, RoleService helper method
HMS17 Aug 16, 2024
3e61b68
Added second GET test and some user setup and teardown
nickpalladino Aug 19, 2024
b584e68
Delete src/main/java/org/breedinginsight/utilities/out.csv
nickpalladino Aug 19, 2024
6556601
Added test for POST with invalid program user id and updated request …
nickpalladino Aug 19, 2024
4f18253
[BI-2256] - GET method, some other fixes
HMS17 Aug 20, 2024
1845cf2
Added post and delete test
nickpalladino Aug 21, 2024
e9fb5fa
[BI-2256] - Switch to using userId, code to retrieve collabId
HMS17 Aug 21, 2024
328fca7
Merge remote-tracking branch 'origin/feature/BI-2256' into feature/BI…
HMS17 Aug 21, 2024
5f7d9e2
Added another get test
nickpalladino Aug 21, 2024
2126274
Merge branch 'develop' into feature/BI-2256
HMS17 Aug 21, 2024
a138f57
Added get after deactivated test
nickpalladino Aug 21, 2024
cd8303b
Merge branch 'feature/BI-2256' of https://github.com/Breeding-Insight…
nickpalladino Aug 21, 2024
05284cc
Simplified test
nickpalladino Aug 21, 2024
7061ed5
Removed comment
nickpalladino Aug 21, 2024
6f9541f
Added response checks for active=false case
nickpalladino Aug 22, 2024
5c050c4
Added response checks for active=true case
nickpalladino Aug 22, 2024
49a4127
[BI-2256] - Cleanup
HMS17 Aug 22, 2024
3ffbdb2
Merge remote-tracking branch 'origin/feature/BI-2256' into feature/BI…
HMS17 Aug 22, 2024
f3beeb0
[BI-2256] - Cleanup and fixing unit test
HMS17 Aug 22, 2024
b7d03f2
[BI-2256] - Removing unused programUserId in response
HMS17 Aug 22, 2024
06aa11d
[BI-2256] - unit test
HMS17 Aug 22, 2024
2254603
[BI-2256] - unit test
HMS17 Aug 22, 2024
ad3c5cb
[BI-2256] - moved tests
HMS17 Aug 27, 2024
2ebbd86
Merge branch 'develop' into feature/BI-2256
nickpalladino Aug 29, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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 userId;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* 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.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.UUID;

@Getter
@Setter
@Accessors(chain=true)
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class ExperimentalCollaboratorResponse {
//collaboratorId is null in case where active=false
private UUID collaboratorId;
@NotNull
private Boolean active;
@NotBlank
private String name;
@NotBlank
private String email;
@NotBlank
private UUID userId;
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,35 @@
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.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;
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.model.Dataset;
import org.breedinginsight.model.DatasetMetadata;
import org.breedinginsight.model.DownloadFile;
import org.breedinginsight.model.Program;
import org.breedinginsight.dao.db.tables.pojos.ExperimentProgramUserRoleEntity;
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.Utilities;
import org.breedinginsight.utilities.response.mappers.ExperimentQueryMapper;

import javax.inject.Inject;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;

@Slf4j
@Controller
Expand All @@ -36,12 +48,20 @@ public class ExperimentController {
private final BrAPITrialService experimentService;
private final ExperimentQueryMapper experimentQueryMapper;
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) {
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*}")
Expand Down Expand Up @@ -129,7 +149,7 @@ public HttpResponse<Response<Dataset>> 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
*/
@Get("/${micronaut.bi.api.version}/programs/{programId}/experiments/{experimentId}/datasets")
@ExperimentCollaboratorSecured
Expand All @@ -148,4 +168,136 @@ public HttpResponse<Response<List<DatasetMetadata>>> getDatasets(
return HttpResponse.ok(response);

}

/**
* 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 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")
@ProgramSecured(roles = {ProgramSecuredRole.PROGRAM_ADMIN, ProgramSecuredRole.SYSTEM_ADMIN})
@Produces(MediaType.APPLICATION_JSON)
public HttpResponse<Response<ExperimentProgramUserRoleEntity>> createExperimentalCollaborator(
@PathVariable("programId") UUID programId,
@PathVariable("experimentId") UUID experimentId,
@Body @Valid ExperimentCollaboratorRequest request
) {
try {
//Check if program exists
Optional<Program> programOptional = programService.getById(programId);
if (programOptional.isEmpty()) {
return HttpResponse.status(HttpStatus.NOT_FOUND, "Program does not exist");
}

//Check if program user exists
Optional<ProgramUser> 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();
Response<ExperimentProgramUserRoleEntity> response = new Response(experimentalCollaboratorService.createExperimentalCollaborator(programUserId,experimentId,createdByUserId));
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 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 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}")
@ProgramSecured(roles = {ProgramSecuredRole.PROGRAM_ADMIN, ProgramSecuredRole.SYSTEM_ADMIN})
@Produces(MediaType.APPLICATION_JSON)
public HttpResponse<Response<DataResponse<List<ExperimentalCollaboratorResponse>>>> getExperimentalCollaborators(
@PathVariable("programId") UUID programId,
@PathVariable("experimentId") UUID experimentId,
@QueryValue(defaultValue = "true") Boolean active
) {
try {
//Get experimental collaborators associated with the experiment
List<ExperimentProgramUserRoleEntity> collaborators = experimentalCollaboratorService.getExperimentalCollaborators(experimentId);
List<UUID> activeCollaboratorIds = collaborators.stream().map((ExperimentProgramUserRoleEntity::getProgramUserRoleId)).collect(Collectors.toList());

//Get roleId for experimental collaborator role
Role experimentalCollabRole = roleService.getRoleByDomain(ProgramSecuredRole.EXPERIMENTAL_COLLABORATOR.toString()).get();
UUID roleId = experimentalCollabRole.getId();

//Get all program users with experimental collaborator role
List<ProgramUser> collabRoleUsers = programUserService.getProgramUsersByRole(programId, roleId);
List<ExperimentalCollaboratorResponse> collaboratorResponses = new ArrayList<>();

for (ProgramUser collabRoleUser : collabRoleUsers) {
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();
}

//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.setUserId(collabRoleUser.getUserId());
collabResponse.setCollaboratorId(collaboratorId);
collaboratorResponses.add(collabResponse);
}
}

List<Status> 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<DataResponse<List<ExperimentalCollaboratorResponse>>> response = new Response(metadata, new DataResponse<>(collaboratorResponses));
return HttpResponse.ok(response);
} catch (Exception e) {
log.info(e.getMessage(), e);
HttpResponse response = HttpResponse.serverError();
return response;
}

}

/**
* Removes record from experiment_program_user_role table
* @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})
@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;
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,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,
Expand All @@ -60,9 +60,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);
Expand Down
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an improvement, thanks!

Original file line number Diff line number Diff line change
Expand Up @@ -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<ExperimentProgramUserRoleEntity> getExperimentalCollaborators(UUID experimentId) {
Expand All @@ -47,7 +47,7 @@ public List<ExperimentProgramUserRoleEntity> 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);
}
}
12 changes: 12 additions & 0 deletions src/main/java/org/breedinginsight/services/RoleService.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -66,4 +69,13 @@ public List<Role> getRolesByIds(List<UUID> roleIds) {
return roles;
}

public Optional<Role> getRoleByDomain(String domain) {
RoleEntity role = dao.fetchByDomain(domain).get(0);
if (role == null) {
return Optional.empty();
}

return Optional.of(new Role(role));
}

}
Loading