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.List;
019import java.util.Map;
020import java.util.Optional;
021
022import org.apache.avalon.framework.parameters.Parameters;
023import org.apache.avalon.framework.service.ServiceException;
024import org.apache.avalon.framework.service.ServiceManager;
025import org.apache.cocoon.environment.ObjectModelHelper;
026import org.apache.cocoon.environment.Redirector;
027import org.apache.cocoon.environment.Request;
028import org.apache.cocoon.environment.SourceResolver;
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.FormAdminDashboardHelper;
034import org.ametys.plugins.forms.question.types.FileQuestionType;
035import org.ametys.plugins.forms.repository.Form;
036import org.ametys.plugins.forms.repository.FormEntry;
037import org.ametys.plugins.forms.repository.FormQuestion;
038import org.ametys.plugins.repository.RepositoryConstants;
039import org.ametys.plugins.repository.data.holder.values.UntouchedValue;
040import org.ametys.plugins.repository.provider.RequestAttributeWorkspaceSelector;
041import org.ametys.runtime.i18n.I18nizableText;
042import org.ametys.runtime.model.View;
043
044import com.google.common.collect.ArrayListMultimap;
045import com.google.common.collect.Multimap;
046
047/**
048 * Action to edit the given form entry
049 */
050public class EditFormEntryAction extends AbstractProcessFormAction
051{
052    /** The form admin dashboard helper */
053    protected FormAdminDashboardHelper _formAdminDashboardHelper;
054    
055    @Override
056    public void service(ServiceManager smanager) throws ServiceException
057    {
058        super.service(smanager);
059        _formAdminDashboardHelper = (FormAdminDashboardHelper) smanager.lookup(FormAdminDashboardHelper.ROLE);
060    }
061    
062    public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws Exception
063    {
064        Request request = ObjectModelHelper.getRequest(objectModel);
065        // Retrieve the current workspace.
066        String currentWsp = RequestAttributeWorkspaceSelector.getForcedWorkspace(request);
067        try
068        {
069            // Force the workspace.
070            RequestAttributeWorkspaceSelector.setForcedWorkspace(request, RepositoryConstants.DEFAULT_WORKSPACE);
071            
072            String entryId = request.getParameter("entryId");
073            if (entryId == null)
074            {
075                throw new IllegalStateException("Impossible to edit entry. No id provided.");
076            }
077            
078            FormEntry entry = _resolver.resolveById(entryId);
079            if (_rightManager.currentUserHasRight(FormEntryDAO.HANDLE_FORMS_ENTRIES_RIGHT_ID, entry) != RightResult.RIGHT_ALLOW || !_formAdminDashboardHelper.hasAvailableActions(entry))
080            {
081                throw new IllegalAccessError("Can't edit the entry with id '" + entryId + "' without convenient rights.");
082            }
083            
084            Optional<Long> currentStepId = Optional.of(_entryDAO.getCurrentStepId(entry));
085            
086            View view = View.of(entry.getModel());
087            Multimap<String, I18nizableText> formErrors = ArrayListMultimap.create();
088            
089            View filteredEntryView = _getRuleFilteredEntryView(entry.getForm(), view, new FormEntryValues(null, entry), currentStepId);
090            
091            Map<String, Object> values = _foAmetysObjectCreationHelper.getFormValues(request, filteredEntryView, "", formErrors);
092            _adaptFormValuesForChoiceList(entry.getForm(), values);
093            _adaptFormValuesForFile(request, entry.getForm(), values);
094            
095            formErrors.putAll(_foAmetysObjectCreationHelper.validateValues(values, filteredEntryView));
096            for (FormQuestion question : entry.getForm().getQuestions())
097            {
098                if (filteredEntryView.hasModelViewItem(question.getNameForForm()))
099                {
100                    question.getType().validateEntryValues(question, values, formErrors, currentStepId);
101                }
102            }
103            
104            if (!formErrors.isEmpty())
105            {
106                request.setAttribute("form", entry.getForm());
107                request.setAttribute("form-errors", formErrors);
108                return null;
109            }
110            
111            entry.synchronizeValues(filteredEntryView, values);
112            _handleComputedValues(entry.getForm().getQuestions(), entry, true);
113            
114            entry.saveChanges();
115        }
116        finally 
117        {
118            // Restore context
119            RequestAttributeWorkspaceSelector.setForcedWorkspace(request, currentWsp);
120        }
121        
122        return EMPTY_MAP;
123    }
124
125    @Override
126    protected List<FormQuestion> _getRuleFilteredQuestions(Form form, FormEntryValues entryValues, Optional<Long> currentStepId)
127    {
128        // Get only writable questions
129        return _formQuestionDAO.getRuleFilteredQuestions(form, entryValues, currentStepId, true, false);
130    }
131    
132    private void _adaptFormValuesForFile(Request request, Form form, Map<String, Object> values)
133    {
134        List<FormQuestion> fileQuestions = form.getQuestions()
135                .stream()
136                .filter(q -> q.getType() instanceof FileQuestionType)
137                .toList();
138            
139        for (FormQuestion question : fileQuestions)
140        {
141            String nameForForm = question.getNameForForm();
142            String fileInfo = request.getParameter(nameForForm + "-info");
143            if ("untouched".equals(fileInfo))
144            {
145                values.put(nameForForm, new UntouchedValue());
146            }
147        }
148    }
149}