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}