diff --git a/gsrs-module-substances-core/src/main/java/gsrs/module/substance/approval/ApprovalIdConfiguration.java b/gsrs-module-substances-core/src/main/java/gsrs/module/substance/approval/ApprovalIdConfiguration.java index 5907302f9..bbff36782 100644 --- a/gsrs-module-substances-core/src/main/java/gsrs/module/substance/approval/ApprovalIdConfiguration.java +++ b/gsrs-module-substances-core/src/main/java/gsrs/module/substance/approval/ApprovalIdConfiguration.java @@ -12,6 +12,7 @@ import org.springframework.context.annotation.Configuration; import java.util.Collections; +import java.util.HashMap; import java.util.Map; @Configuration @@ -22,13 +23,17 @@ public class ApprovalIdConfiguration { private Class generatorClass; private Map parameters; + private Map validators; @Bean @ConditionalOnMissingBean public ApprovalService defaultApprovalService(SubstanceApprovalIdGenerator approvalIdGenerator, SubstanceRepository substanceRepository, PrincipalRepository principalRepository){ - return new DefaultApprovalService(approvalIdGenerator, substanceRepository, principalRepository); + if (validators == null) { + validators = new HashMap(); + } + return new DefaultApprovalService(approvalIdGenerator, substanceRepository, principalRepository, validators); } @Bean diff --git a/gsrs-module-substances-core/src/main/java/gsrs/module/substance/approval/ApprovalService.java b/gsrs-module-substances-core/src/main/java/gsrs/module/substance/approval/ApprovalService.java index 8dc6df367..8b78056a4 100644 --- a/gsrs-module-substances-core/src/main/java/gsrs/module/substance/approval/ApprovalService.java +++ b/gsrs-module-substances-core/src/main/java/gsrs/module/substance/approval/ApprovalService.java @@ -9,6 +9,8 @@ public interface ApprovalService { + boolean isApprovable(Substance s); + ApprovalResult approve(Substance s) throws ApprovalException; @Data diff --git a/gsrs-module-substances-core/src/main/java/gsrs/module/substance/approval/DefaultApprovalService.java b/gsrs-module-substances-core/src/main/java/gsrs/module/substance/approval/DefaultApprovalService.java index 9ecfdaa83..38bdde042 100644 --- a/gsrs-module-substances-core/src/main/java/gsrs/module/substance/approval/DefaultApprovalService.java +++ b/gsrs-module-substances-core/src/main/java/gsrs/module/substance/approval/DefaultApprovalService.java @@ -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; /** @@ -38,13 +40,24 @@ public class DefaultApprovalService implements ApprovalService{ private PrincipalRepository principalRepository; + private Map validators; + @Autowired public DefaultApprovalService(SubstanceApprovalIdGenerator approvalIdGenerator, SubstanceRepository substanceRepository, - PrincipalRepository principalRepository) { + PrincipalRepository principalRepository, + Map validators) { this.approvalIdGenerator = approvalIdGenerator; this.substanceRepository = substanceRepository; this.principalRepository = principalRepository; + Map vMap = new HashMap(); + 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; } /** @@ -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 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. diff --git a/gsrs-module-substances-core/src/main/java/gsrs/module/substance/controllers/SubstanceController.java b/gsrs-module-substances-core/src/main/java/gsrs/module/substance/controllers/SubstanceController.java index 1df712628..282cf9f68 100644 --- a/gsrs-module-substances-core/src/main/java/gsrs/module/substance/controllers/SubstanceController.java +++ b/gsrs-module-substances-core/src/main/java/gsrs/module/substance/controllers/SubstanceController.java @@ -1036,6 +1036,17 @@ public void saveTempStructure(Structure s) { } + @GetGsrsRestApiMapping(value={"({id})/@isApprovable", "/{id}/@isApprovable" }) + public ResponseEntity isApprovableGetMethod(@PathVariable("id") String substanceUUIDOrName, @RequestParam Map queryParameters) throws Exception { + Optional 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