001/*
002 *  Copyright 2023 Anyware Services
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 */
016package org.ametys.plugins.forms.actions;
017
018import java.util.HashMap;
019import java.util.List;
020import java.util.Map;
021import java.util.Optional;
022
023import org.apache.avalon.framework.parameters.Parameters;
024import org.apache.cocoon.environment.ObjectModelHelper;
025import org.apache.cocoon.environment.Redirector;
026import org.apache.cocoon.environment.Request;
027import org.apache.cocoon.environment.SourceResolver;
028import org.apache.commons.lang3.StringUtils;
029
030import org.ametys.core.right.RightManager.RightResult;
031import org.ametys.plugins.forms.dao.FormEntryDAO;
032import org.ametys.plugins.forms.dao.FormQuestionDAO.FormEntryValues;
033import org.ametys.plugins.forms.helper.FormWorkflowHelper;
034import org.ametys.plugins.forms.repository.Form;
035import org.ametys.plugins.forms.repository.FormEntry;
036import org.ametys.plugins.forms.repository.FormQuestion;
037import org.ametys.plugins.repository.RepositoryConstants;
038import org.ametys.plugins.repository.provider.RequestAttributeWorkspaceSelector;
039import org.ametys.runtime.i18n.I18nizableText;
040
041import com.google.common.collect.ArrayListMultimap;
042import com.google.common.collect.Multimap;
043
044/**
045 * Action to edit the given form entry
046 */
047public class EditFormEntryAction extends AbstractProcessFormAction
048{
049    public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws Exception
050    {
051        Request request = ObjectModelHelper.getRequest(objectModel);
052        // Retrieve the current workspace.
053        String currentWsp = RequestAttributeWorkspaceSelector.getForcedWorkspace(request);
054        try
055        {
056            // Force the workspace.
057            RequestAttributeWorkspaceSelector.setForcedWorkspace(request, RepositoryConstants.DEFAULT_WORKSPACE);
058            
059            String entryId = request.getParameter("entryId");
060            if (entryId == null)
061            {
062                throw new IllegalStateException("Impossible to edit entry. No id provided.");
063            }
064            
065            Multimap<String, I18nizableText> formErrors = ArrayListMultimap.create();
066            FormEntry entry = _resolver.resolveById(entryId);
067            boolean canSubmitterEdit = _canSubmitterEdit(entry);
068            if (!canSubmitterEdit && !_canManagerEdit(entry))
069            {
070                formErrors.put("form-access", new I18nizableText("plugin.forms", "PLUGINS_FORMS_EDIT_FORM_ENTRY_ERRORS"));
071                request.setAttribute("form", entry.getForm());
072                request.setAttribute("form-errors", formErrors);
073                return null;
074            }
075            
076            Optional<Long> currentStepId = Optional.of(_entryDAO.getCurrentStepId(entry));
077            
078            Map<String, Object> additionalParameters = new HashMap<>();
079            additionalParameters.put("ignoreWriteRestriction", canSubmitterEdit);
080            formErrors.putAll(editFormEntryValues(request, entry, currentStepId, additionalParameters, false));
081            
082            if (!formErrors.isEmpty())
083            {
084                request.setAttribute("form", entry.getForm());
085                request.setAttribute("form-errors", formErrors);
086                return null;
087            }
088        }
089        finally
090        {
091            // Restore context
092            RequestAttributeWorkspaceSelector.setForcedWorkspace(request, currentWsp);
093        }
094        
095        return EMPTY_MAP;
096    }
097
098    @Override
099    protected List<FormQuestion> _getRuleFilteredQuestions(Request request, Form form, FormEntryValues entryValues, Optional<Long> currentStepId)
100    {
101        String isSubmitterAsString = request.getParameter("isSubmitter");
102        boolean isSubmitter = StringUtils.isNotBlank(isSubmitterAsString) ? Boolean.valueOf(isSubmitterAsString) : false;
103        
104        boolean canSubmitterEdit = isSubmitter && _canSubmitterEdit(entryValues.entry());
105        boolean onlyWritableQuestion = !canSubmitterEdit; // Get only writable questions if it's not the submitter
106        boolean onlyReadableQuestion = canSubmitterEdit; // Get only readable questions if it's the submitter
107        
108        return _formQuestionDAO.getRuleFilteredQuestions(form, entryValues, currentStepId, onlyWritableQuestion, onlyReadableQuestion)
109                .stream()
110                .filter(q -> !canSubmitterEdit || _formQuestionDAO.canSubmitterEditSubmission(q)) // If the submitter is editing the entry, check is the question can be edited by the submitter
111                .toList();
112    }
113    
114    private boolean _canManagerEdit(FormEntry entry)
115    {
116        // Manager can edit if the edit action is available and he has the right to handle the entry
117        return _rightManager.currentUserHasRight(FormEntryDAO.HANDLE_FORMS_ENTRIES_RIGHT_ID, entry) == RightResult.RIGHT_ALLOW
118                && !_formWorkflowHelper.getAvailableActionsRestrictedToTypes(entry, List.of(FormWorkflowHelper.EDIT_ACTION)).isEmpty();
119    }
120    
121    private boolean _canSubmitterEdit(FormEntry entry)
122    {
123        // Submitter can edit if the edit-by-submitter action is available and he is the entry submitter
124        return _currentUserProvider.getUser().equals(entry.getUser())
125                && !_formWorkflowHelper.getAvailableActionsRestrictedToTypes(entry, List.of(FormWorkflowHelper.EDIT_BY_SUBMITTER_ACTION)).isEmpty();
126    }
127}