001// -------------------------------------------------------------------------------- 002// Copyright 2002-2025 Echo Three, LLC 003// 004// Licensed under the Apache License, Version 2.0 (the "License"); 005// you may not use this file except in compliance with the License. 006// You may obtain a copy of the License at 007// 008// http://www.apache.org/licenses/LICENSE-2.0 009// 010// Unless required by applicable law or agreed to in writing, software 011// distributed under the License is distributed on an "AS IS" BASIS, 012// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013// See the License for the specific language governing permissions and 014// limitations under the License. 015// -------------------------------------------------------------------------------- 016 017package com.echothree.model.control.workflow.server.logic; 018 019import com.echothree.model.control.security.server.control.SecurityControl; 020import com.echothree.model.control.workflow.server.control.WorkflowControl; 021import com.echothree.model.data.party.common.pk.PartyPK; 022import com.echothree.model.data.party.server.factory.PartyFactory; 023import com.echothree.model.data.workflow.server.entity.WorkflowDestination; 024import com.echothree.model.data.workflow.server.entity.WorkflowEntrance; 025import com.echothree.util.common.message.ExecutionErrors; 026import com.echothree.util.server.message.ExecutionErrorAccumulator; 027import com.echothree.util.server.persistence.EntityPermission; 028import com.echothree.util.server.persistence.Session; 029import javax.enterprise.context.ApplicationScoped; 030import javax.enterprise.inject.spi.CDI; 031 032@ApplicationScoped 033public class WorkflowSecurityLogic { 034 035 protected WorkflowSecurityLogic() { 036 super(); 037 } 038 039 public static WorkflowSecurityLogic getInstance() { 040 return CDI.current().select(WorkflowSecurityLogic.class).get(); 041 } 042 043 public boolean checkWorkflowEntranceAvailable(final WorkflowEntrance workflowEntrance, final PartyPK partyPK) { 044 var workflowControl = Session.getModelController(WorkflowControl.class); 045 var checkPassed = false; 046 047 if(workflowControl.countWorkflowEntrancePartyTypesByWorkflowEntrance(workflowEntrance) != 0) { 048 var party = PartyFactory.getInstance().getEntityFromPK(EntityPermission.READ_ONLY, partyPK); 049 var partyType = party.getLastDetail().getPartyType(); 050 var workflowEntrancePartyType = workflowControl.getWorkflowEntrancePartyType(workflowEntrance, partyType); 051 052 if(workflowEntrancePartyType != null) { 053 var securityControl = Session.getModelController(SecurityControl.class); 054 var workflowEntranceSecurityRoles = workflowControl.getWorkflowEntranceSecurityRolesByWorkflowEntrancePartyType(workflowEntrancePartyType); 055 056 if(workflowEntranceSecurityRoles.isEmpty()) { 057 // If there are no individual Security Roles, then pass it since the user is in a Party Type that was found. 058 checkPassed = true; 059 } else { 060 // Otherwise, check each individual Security Role. 061 for(var workflowEntranceSecurityRole : workflowEntranceSecurityRoles) { 062 if(securityControl.partySecurityRoleExists(partyPK, workflowEntranceSecurityRole.getSecurityRolePK())) { 063 // The Party has one of the required Security Roles, allow the transition and stop further checking. 064 checkPassed = true; 065 break; 066 } 067 } 068 } 069 } 070 } else { 071 // If there are no Workflow Entrance Party Types, then allow the transition. 072 checkPassed = true; 073 } 074 075 return checkPassed; 076 } 077 078 public boolean checkAddEntityToWorkflow(final ExecutionErrorAccumulator eea, final WorkflowEntrance workflowEntrance, final PartyPK modifiedBy) { 079 var checkPassed = checkWorkflowEntranceAvailable(workflowEntrance, modifiedBy); 080 081 if(!checkPassed) { 082 eea.addExecutionError(ExecutionErrors.WorkflowEntranceNotAllowed.name()); 083 } 084 085 return checkPassed; 086 } 087 088 public boolean checkWorkflowDestinationAvailable(final WorkflowDestination workflowDestination, final PartyPK partyPK) { 089 var workflowControl = Session.getModelController(WorkflowControl.class); 090 var checkPassed = false; 091 092 if(workflowControl.countWorkflowDestinationPartyTypes(workflowDestination) != 0) { 093 var party = PartyFactory.getInstance().getEntityFromPK(EntityPermission.READ_ONLY, partyPK); 094 var partyType = party.getLastDetail().getPartyType(); 095 var workflowDestinationPartyType = workflowControl.getWorkflowDestinationPartyType(workflowDestination, partyType); 096 097 if(workflowDestinationPartyType != null) { 098 var securityControl = Session.getModelController(SecurityControl.class); 099 var workflowDestinationSecurityRoles = workflowControl.getWorkflowDestinationSecurityRolesByWorkflowDestinationPartyType(workflowDestinationPartyType); 100 101 if(workflowDestinationSecurityRoles.isEmpty()) { 102 // If there are no individual Security Roles, then pass it since the user is in a Party Type that was found. 103 checkPassed = true; 104 } else { 105 // Otherwise, check each individual Security Role. 106 for(var workflowDestinationSecurityRole : workflowDestinationSecurityRoles) { 107 if(securityControl.partySecurityRoleExists(partyPK, workflowDestinationSecurityRole.getSecurityRolePK())) { 108 // The Party has one of the required Security Roles, allow the transition and stop further checking. 109 checkPassed = true; 110 break; 111 } 112 } 113 } 114 } 115 } else { 116 // If there are no Workflow Destination Party Types, then allow the transition. 117 checkPassed = true; 118 } 119 120 return checkPassed; 121 } 122 123 public boolean checkTransitionEntityInWorkflow(final ExecutionErrorAccumulator eea, final WorkflowDestination workflowDestination, final PartyPK modifiedBy) { 124 var checkPassed = checkWorkflowDestinationAvailable(workflowDestination, modifiedBy); 125 126 if(!checkPassed) { 127 eea.addExecutionError(ExecutionErrors.WorkflowDestinationNotAllowed.name()); 128 } 129 130 return checkPassed; 131 } 132 133}