001// --------------------------------------------------------------------------------
002// Copyright 2002-2026 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 javax.enterprise.context.ApplicationScoped;
029import javax.inject.Inject;
030
031@ApplicationScoped
032public class WorkflowSecurityLogic {
033
034    @Inject
035    PartyFactory partyFactory;
036
037    @Inject
038    SecurityControl securityControl;
039
040    @Inject
041    WorkflowControl workflowControl;
042
043    protected WorkflowSecurityLogic() {
044        super();
045    }
046    
047    public boolean checkWorkflowEntranceAvailable(final WorkflowEntrance workflowEntrance, final PartyPK partyPK) {
048        var checkPassed = false;
049
050        if(workflowControl.countWorkflowEntrancePartyTypesByWorkflowEntrance(workflowEntrance) != 0) {
051            var party = partyFactory.getEntityFromPK(EntityPermission.READ_ONLY, partyPK);
052            var partyType = party.getLastDetail().getPartyType();
053            var workflowEntrancePartyType = workflowControl.getWorkflowEntrancePartyType(workflowEntrance, partyType);
054
055            if(workflowEntrancePartyType != null) {
056                var workflowEntranceSecurityRoles = workflowControl.getWorkflowEntranceSecurityRolesByWorkflowEntrancePartyType(workflowEntrancePartyType);
057
058                if(workflowEntranceSecurityRoles.isEmpty()) {
059                    // If there are no individual Security Roles, then pass it since the user is in a Party Type that was found.
060                    checkPassed = true;
061                } else {
062                    // Otherwise, check each individual Security Role.
063                    for(var workflowEntranceSecurityRole : workflowEntranceSecurityRoles) {
064                        if(securityControl.partySecurityRoleExists(partyPK, workflowEntranceSecurityRole.getSecurityRolePK())) {
065                            // The Party has one of the required Security Roles, allow the transition and stop further checking.
066                            checkPassed = true;
067                            break;
068                        }
069                    }
070                }
071            }
072        } else {
073            // If there are no Workflow Entrance Party Types, then allow the transition.
074            checkPassed = true;
075        }
076
077        return checkPassed;
078    }
079
080    public boolean checkAddEntityToWorkflow(final ExecutionErrorAccumulator eea, final WorkflowEntrance workflowEntrance, final PartyPK modifiedBy) {
081        var checkPassed = checkWorkflowEntranceAvailable(workflowEntrance, modifiedBy);
082        
083        if(!checkPassed) {
084            eea.addExecutionError(ExecutionErrors.WorkflowEntranceNotAllowed.name());
085        }
086
087        return checkPassed;
088    }
089
090    public boolean checkWorkflowDestinationAvailable(final WorkflowDestination workflowDestination, final PartyPK partyPK) {
091        var checkPassed = false;
092
093        if(workflowControl.countWorkflowDestinationPartyTypes(workflowDestination) != 0) {
094            var party = partyFactory.getEntityFromPK(EntityPermission.READ_ONLY, partyPK);
095            var partyType = party.getLastDetail().getPartyType();
096            var workflowDestinationPartyType = workflowControl.getWorkflowDestinationPartyType(workflowDestination, partyType);
097
098            if(workflowDestinationPartyType != null) {
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}