Skip to content

Commit

Permalink
Merge pull request #334 from ncats/apiIsApprovable
Browse files Browse the repository at this point in the history
Make ApprovalValidations more configurable
  • Loading branch information
blueSwordfish authored May 31, 2024
2 parents aed7ba9 + 67e9959 commit 9f8261b
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import org.springframework.context.annotation.Configuration;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

@Configuration
Expand All @@ -22,13 +23,17 @@ public class ApprovalIdConfiguration {

private Class generatorClass;
private Map<String, Object> parameters;
private Map<String, Boolean> validators;

@Bean
@ConditionalOnMissingBean
public ApprovalService defaultApprovalService(SubstanceApprovalIdGenerator approvalIdGenerator,
SubstanceRepository substanceRepository,
PrincipalRepository principalRepository){
return new DefaultApprovalService(approvalIdGenerator, substanceRepository, principalRepository);
if (validators == null) {
validators = new HashMap<String, Boolean>();
}
return new DefaultApprovalService(approvalIdGenerator, substanceRepository, principalRepository, validators);

}
@Bean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

public interface ApprovalService {

boolean isApprovable(Substance s);

ApprovalResult approve(Substance s) throws ApprovalException;

@Data
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

/**
Expand All @@ -38,13 +40,24 @@ public class DefaultApprovalService implements ApprovalService{

private PrincipalRepository principalRepository;

private Map<String, Boolean> validators;

@Autowired
public DefaultApprovalService(SubstanceApprovalIdGenerator approvalIdGenerator,
SubstanceRepository substanceRepository,
PrincipalRepository principalRepository) {
PrincipalRepository principalRepository,
Map<String, Boolean> validators) {
this.approvalIdGenerator = approvalIdGenerator;
this.substanceRepository = substanceRepository;
this.principalRepository = principalRepository;
Map<String, Boolean> vMap = new HashMap<String, Boolean>();
vMap.put("allowLastEditor", validators.getOrDefault("allowLastEditor", Boolean.FALSE));
vMap.put("allowCreator", validators.getOrDefault("allowCreator", Boolean.FALSE));
vMap.put("allowNonPrimary", validators.getOrDefault("allowNonPrimary", Boolean.FALSE));
vMap.put("allowConcept", validators.getOrDefault("allowConcept", Boolean.FALSE));
vMap.put("allowDependsOnNonPresent", validators.getOrDefault("allowDependsOnNonPresent", Boolean.FALSE));
vMap.put("allowDependsOnNonApproved", validators.getOrDefault("allowDependsOnNonApproved", Boolean.FALSE));
this.validators = vMap;
}

/**
Expand Down Expand Up @@ -100,30 +113,52 @@ protected void defaultApprovalValidation(Substance s, String usernameOfApprover)
throw new ApprovalException(
"There is no last editor associated with this record. One must be present to allow approval. Please contact your system administrator.");
} else {
if (s.lastEditedBy.username.equals(usernameOfApprover)) {
throw new ApprovalException(
if (validators.get("allowLastEditor") == Boolean.FALSE && s.lastEditedBy.username.equals(usernameOfApprover)) {
if (!(validators.get("allowCreator") == Boolean.TRUE && s.createdBy != null && s.createdBy.username.equals(usernameOfApprover))) {
throw new ApprovalException(
"You cannot approve a substance if you are the last editor of the substance.");
}
}
}
if (!s.isPrimaryDefinition()) {
if (validators.get("allowNonPrimary") == Boolean.FALSE && !s.isPrimaryDefinition()) {
throw new ApprovalException("Cannot approve non-primary definitions.");
}
if (Substance.SubstanceClass.concept.equals(s.substanceClass)) {
if (validators.get("allowConcept") == Boolean.FALSE && Substance.SubstanceClass.concept.equals(s.substanceClass)) {
throw new ApprovalException("Cannot approve non-substance concepts.");
}
for (SubstanceReference sr : s.getDependsOnSubstanceReferences()) {
Optional<SubstanceRepository.SubstanceSummary> s2 = substanceRepository.findSummaryBySubstanceReference(sr);
if (!s2.isPresent()) {
if (validators.get("allowDependsOnNonPresent") == Boolean.FALSE && !s2.isPresent()) {
throw new IllegalStateException("Cannot approve substance that depends on " + sr.toString()
+ " which is not found in database.");
}
if (!s2.get().isValidated()) {
if (validators.get("allowDependsOnNonApproved") == Boolean.FALSE && !s2.get().isValidated()) {
throw new IllegalStateException(
"Cannot approve substance that depends on " + sr.toString() + " which is not approved.");
}
}
}

/**
* Check if the given Substance is approvable by the user invoking this method.
* @param s the Substance to approve.
* @return a true if the user invoking this method is able to approve given Substance.
*/
@Override
public boolean isApprovable(Substance s) {
String userName = GsrsSecurityUtils.getCurrentUsername().orElse(null);
if (userName == null) {
return false;
}
try {
defaultApprovalValidation(s, userName);
extraApprovalValidation(s, userName);
return true;
} catch (ApprovalException ex) {
return false;
}
}

/**
* Try to approve the given Substance. The user invoking this method
* must have Approver Role.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1036,6 +1036,17 @@ public void saveTempStructure(Structure s) {

}

@GetGsrsRestApiMapping(value={"({id})/@isApprovable", "/{id}/@isApprovable" })
public ResponseEntity isApprovableGetMethod(@PathVariable("id") String substanceUUIDOrName, @RequestParam Map<String, String> queryParameters) throws Exception {
Optional<Substance> substance = getEntityService().getEntityBySomeIdentifier(substanceUUIDOrName);

if(!substance.isPresent()){
return getGsrsControllerConfiguration().handleNotFound(queryParameters);
}
boolean approvable = approvalService.isApprovable(substance.get());
return new ResponseEntity<>(String.valueOf(approvable), HttpStatus.OK);
}

@Transactional
@GetGsrsRestApiMapping(value={"({id})/@approve", "/{id}/@approve" })
@hasApproverRole
Expand Down

0 comments on commit 9f8261b

Please sign in to comment.