001// -------------------------------------------------------------------------------- 002// Copyright 2002-2024 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.entity.Party; 023import com.echothree.model.data.party.server.entity.PartyType; 024import com.echothree.model.data.party.server.factory.PartyFactory; 025import com.echothree.model.data.workflow.server.entity.WorkflowDestination; 026import com.echothree.model.data.workflow.server.entity.WorkflowDestinationPartyType; 027import com.echothree.model.data.workflow.server.entity.WorkflowDestinationSecurityRole; 028import com.echothree.model.data.workflow.server.entity.WorkflowEntrance; 029import com.echothree.model.data.workflow.server.entity.WorkflowEntrancePartyType; 030import com.echothree.model.data.workflow.server.entity.WorkflowEntranceSecurityRole; 031import com.echothree.util.common.message.ExecutionErrors; 032import com.echothree.util.server.message.ExecutionErrorAccumulator; 033import com.echothree.util.server.persistence.EntityPermission; 034import com.echothree.util.server.persistence.Session; 035import java.util.List; 036 037public class WorkflowSecurityLogic { 038 039 private WorkflowSecurityLogic() { 040 super(); 041 } 042 043 private static class WorkflowSecurityLogicHolder { 044 static WorkflowSecurityLogic instance = new WorkflowSecurityLogic(); 045 } 046 047 public static WorkflowSecurityLogic getInstance() { 048 return WorkflowSecurityLogicHolder.instance; 049 } 050 051 public boolean checkWorkflowEntranceAvailable(final WorkflowEntrance workflowEntrance, final PartyPK partyPK) { 052 var workflowControl = Session.getModelController(WorkflowControl.class); 053 boolean checkPassed = false; 054 055 if(workflowControl.countWorkflowEntrancePartyTypesByWorkflowEntrance(workflowEntrance) != 0) { 056 Party party = PartyFactory.getInstance().getEntityFromPK(EntityPermission.READ_ONLY, partyPK); 057 PartyType partyType = party.getLastDetail().getPartyType(); 058 WorkflowEntrancePartyType workflowEntrancePartyType = workflowControl.getWorkflowEntrancePartyType(workflowEntrance, partyType); 059 060 if(workflowEntrancePartyType != null) { 061 var securityControl = Session.getModelController(SecurityControl.class); 062 List<WorkflowEntranceSecurityRole> workflowEntranceSecurityRoles = workflowControl.getWorkflowEntranceSecurityRolesByWorkflowEntrancePartyType(workflowEntrancePartyType); 063 064 if(workflowEntranceSecurityRoles.isEmpty()) { 065 // If there are no individual Security Roles, then pass it since the user is in a Party Type that was found. 066 checkPassed = true; 067 } else { 068 // Otherwise, check each individual Security Role. 069 for(var workflowEntranceSecurityRole : workflowEntranceSecurityRoles) { 070 if(securityControl.partySecurityRoleExists(partyPK, workflowEntranceSecurityRole.getSecurityRolePK())) { 071 // The Party has one of the required Security Roles, allow the transition and stop further checking. 072 checkPassed = true; 073 break; 074 } 075 } 076 } 077 } 078 } else { 079 // If there are no Workflow Entrance Party Types, then allow the transition. 080 checkPassed = true; 081 } 082 083 return checkPassed; 084 } 085 086 public boolean checkAddEntityToWorkflow(final ExecutionErrorAccumulator eea, final WorkflowEntrance workflowEntrance, final PartyPK modifiedBy) { 087 boolean checkPassed = checkWorkflowEntranceAvailable(workflowEntrance, modifiedBy); 088 089 if(!checkPassed) { 090 eea.addExecutionError(ExecutionErrors.WorkflowEntranceNotAllowed.name()); 091 } 092 093 return checkPassed; 094 } 095 096 public boolean checkWorkflowDestinationAvailable(final WorkflowDestination workflowDestination, final PartyPK partyPK) { 097 var workflowControl = Session.getModelController(WorkflowControl.class); 098 boolean checkPassed = false; 099 100 if(workflowControl.countWorkflowDestinationPartyTypes(workflowDestination) != 0) { 101 Party party = PartyFactory.getInstance().getEntityFromPK(EntityPermission.READ_ONLY, partyPK); 102 PartyType partyType = party.getLastDetail().getPartyType(); 103 WorkflowDestinationPartyType workflowDestinationPartyType = workflowControl.getWorkflowDestinationPartyType(workflowDestination, partyType); 104 105 if(workflowDestinationPartyType != null) { 106 var securityControl = Session.getModelController(SecurityControl.class); 107 List<WorkflowDestinationSecurityRole> workflowDestinationSecurityRoles = workflowControl.getWorkflowDestinationSecurityRolesByWorkflowDestinationPartyType(workflowDestinationPartyType); 108 109 if(workflowDestinationSecurityRoles.isEmpty()) { 110 // If there are no individual Security Roles, then pass it since the user is in a Party Type that was found. 111 checkPassed = true; 112 } else { 113 // Otherwise, check each individual Security Role. 114 for(var workflowDestinationSecurityRole : workflowDestinationSecurityRoles) { 115 if(securityControl.partySecurityRoleExists(partyPK, workflowDestinationSecurityRole.getSecurityRolePK())) { 116 // The Party has one of the required Security Roles, allow the transition and stop further checking. 117 checkPassed = true; 118 break; 119 } 120 } 121 } 122 } 123 } else { 124 // If there are no Workflow Destination Party Types, then allow the transition. 125 checkPassed = true; 126 } 127 128 return checkPassed; 129 } 130 131 public boolean checkTransitionEntityInWorkflow(final ExecutionErrorAccumulator eea, final WorkflowDestination workflowDestination, final PartyPK modifiedBy) { 132 boolean checkPassed = checkWorkflowDestinationAvailable(workflowDestination, modifiedBy); 133 134 if(!checkPassed) { 135 eea.addExecutionError(ExecutionErrors.WorkflowDestinationNotAllowed.name()); 136 } 137 138 return checkPassed; 139 } 140 141}