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.user.server.logic;
018
019import com.echothree.model.control.order.server.control.OrderControl;
020import com.echothree.model.control.search.server.control.SearchControl;
021import com.echothree.model.control.user.server.control.UserControl;
022import com.echothree.model.control.workrequirement.server.logic.WorkRequirementLogic;
023import com.echothree.model.data.party.common.pk.PartyPK;
024import com.echothree.model.data.user.common.pk.UserVisitPK;
025import com.echothree.model.data.user.server.entity.UserKey;
026import com.echothree.model.data.user.server.entity.UserSession;
027import com.echothree.model.data.user.server.entity.UserVisit;
028import com.echothree.model.data.user.server.factory.UserVisitFactory;
029import com.echothree.model.data.user.server.value.UserKeyDetailValue;
030import com.echothree.util.server.control.BaseLogic;
031import com.echothree.util.server.persistence.EntityPermission;
032import com.echothree.util.server.persistence.Session;
033
034public class UserVisitLogic
035        extends BaseLogic {
036    
037    private UserVisitLogic() {
038        super();
039    }
040    
041    private static class UserVisitLogicHolder {
042        static UserVisitLogic instance = new UserVisitLogic();
043    }
044    
045    public static UserVisitLogic getInstance() {
046        return UserVisitLogicHolder.instance;
047    }
048    
049    private void cleanupUserVisitDependencies(final UserVisit userVisit, final Long endTime, final PartyPK cleanedUpBy) {
050        var orderControl = Session.getModelController(OrderControl.class);
051        var searchControl = Session.getModelController(SearchControl.class);
052
053        orderControl.deleteOrderUserVisitsByUserVisit(userVisit);
054
055        // Clear any searches since they may contain results that should not be accessible by another user.
056        searchControl.removeUserVisitSearchesByUserVisit(userVisit);
057
058        WorkRequirementLogic.getInstance().endWorkTimesByUserVisit(userVisit, endTime, cleanedUpBy);
059    }
060    
061    public void invalidateUserVisit(UserVisit userVisit, PartyPK invalidatedBy) {
062        if(userVisit != null) {
063            var userControl = Session.getModelController(UserControl.class);
064            UserSession userSession = UserSessionLogic.getInstance().deleteUserSessionByUserVisit(userVisit);
065            
066            cleanupUserVisitDependencies(userVisit, null, invalidatedBy);
067            
068            if(userVisit.getRetainUntilTime() == null) {
069                if(userSession != null) {
070                    userControl.removeUserSession(userSession);
071                }
072                
073                userControl.removeUserVisit(userVisit);
074            } else {
075                userControl.deleteUserVisit(userVisit);
076            }
077        }
078    }
079    
080    public void invalidateUserVisit(UserVisitPK userVisitPK, PartyPK invalidatedBy) {
081        var userControl = Session.getModelController(UserControl.class);
082        
083        invalidateUserVisit(userControl.getUserVisitByPKForUpdate(userVisitPK), invalidatedBy);
084    }
085    
086    public void invalidateAbandonedUserVisits(Long abandonedTime, PartyPK invalidatedBy) {
087        var userControl = Session.getModelController(UserControl.class);
088        
089        for(UserVisit userVisit: userControl.getAbandonedUserVisits(abandonedTime)) {
090            userVisit = UserVisitFactory.getInstance().getEntityFromPK(EntityPermission.READ_WRITE, userVisit.getPrimaryKey());
091            
092            invalidateUserVisit(userVisit, invalidatedBy);
093        }
094    }
095    
096    public void removeInvalidatedUserVisits() {
097        var userControl = Session.getModelController(UserControl.class);
098        
099        for(UserVisit userVisit: userControl.getInvalidatedUserVisits()) {
100            userVisit = UserVisitFactory.getInstance().getEntityFromPK(EntityPermission.READ_WRITE, userVisit.getPrimaryKey());
101            
102            userControl.removeUserVisit(userVisit);
103        }
104    }
105    
106    /** Disassociate any Party from the specified UserVisit by deleting the UserSession, keep all the Preferred* properties.
107     */
108    public void disassociatePartyFromUserVisit(final UserVisit userVisit, final Long endTime, final PartyPK disassociatedBy) {
109        var userControl = Session.getModelController(UserControl.class);
110        UserSession userSession = userControl.getUserSessionByUserVisitForUpdate(userVisit);
111        
112        if(userSession != null) {
113            // If there wasn't a specific UserSession and Party assocaited with the UserVisit,
114            // then we shouldn't need to perform this step.
115            cleanupUserVisitDependencies(userVisit, endTime, disassociatedBy);
116
117            userControl.deleteUserSession(userSession);
118        }
119    }
120    
121    /** Remove any Party's specific connection to the UserVisit and its UserKey. Clearing the connection in the UserKey is one step beyond
122     * what's provided by disassociatePartyFromUserVisit(...).
123     */
124    public void logout(final UserVisitPK userVisitPK, final Long endTime, final PartyPK loggedOutBy) {
125        var userControl = Session.getModelController(UserControl.class);
126        UserVisit userVisit = userControl.getUserVisitByPK(userVisitPK);
127        UserKey userKey = userVisit.getUserKey();
128        UserKeyDetailValue userKeyDetailValue = userControl.getUserKeyDetailValueByPKForUpdate(userKey.getLastDetail().getPrimaryKey());
129
130        if(userKeyDetailValue.getPartyPK() != null || userKeyDetailValue.getPartyRelationshipPK() != null) {
131            userKeyDetailValue.setPartyPK(null);
132            userKeyDetailValue.setPartyRelationshipPK(null);
133            userControl.updateUserKeyFromValue(userKeyDetailValue);
134        }
135
136        disassociatePartyFromUserVisit(userVisit, endTime, loggedOutBy);
137
138        // TODO: Create audit trail
139    }
140    
141}