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.service.ServiceException; 023import org.apache.avalon.framework.service.ServiceManager; 024import org.apache.cocoon.acting.ServiceableAction; 025 026import org.ametys.core.right.RightManager; 027import org.ametys.plugins.forms.dao.FormDAO; 028import org.ametys.plugins.forms.dao.FormEntryDAO; 029import org.ametys.plugins.forms.dao.FormQuestionDAO; 030import org.ametys.plugins.forms.dao.FormQuestionDAO.FormEntryValues; 031import org.ametys.plugins.forms.question.FormQuestionType; 032import org.ametys.plugins.forms.question.sources.ChoiceSourceType; 033import org.ametys.plugins.forms.question.types.ChoicesListQuestionType; 034import org.ametys.plugins.forms.question.types.ComputedQuestionType; 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.AmetysObjectResolver; 039import org.ametys.runtime.model.View; 040import org.ametys.runtime.model.ViewItem; 041import org.ametys.web.FOAmetysObjectCreationHelper; 042 043/** 044 * Abstract action to process form entry inputs 045 */ 046public abstract class AbstractProcessFormAction extends ServiceableAction 047{ 048 /** The ametys object resolver */ 049 protected AmetysObjectResolver _resolver; 050 051 /** The FO ametys object creation helper */ 052 protected FOAmetysObjectCreationHelper _foAmetysObjectCreationHelper; 053 054 /** The form DAO */ 055 protected FormDAO _formDAO; 056 057 /** The form entry DAO */ 058 protected FormEntryDAO _entryDAO; 059 060 /** The form question DAO */ 061 protected FormQuestionDAO _formQuestionDAO; 062 063 /** The right manager */ 064 protected RightManager _rightManager; 065 066 @Override 067 public void service(ServiceManager smanager) throws ServiceException 068 { 069 super.service(smanager); 070 _foAmetysObjectCreationHelper = (FOAmetysObjectCreationHelper) smanager.lookup(FOAmetysObjectCreationHelper.ROLE); 071 _resolver = (AmetysObjectResolver) smanager.lookup(AmetysObjectResolver.ROLE); 072 _formDAO = (FormDAO) smanager.lookup(FormDAO.ROLE); 073 _entryDAO = (FormEntryDAO) smanager.lookup(FormEntryDAO.ROLE); 074 _formQuestionDAO = (FormQuestionDAO) smanager.lookup(FormQuestionDAO.ROLE); 075 _rightManager = (RightManager) smanager.lookup(RightManager.ROLE); 076 } 077 078 /** 079 * Remove empty value for choice list because empty value is an other value 080 * @param form the form 081 * @param formInputValues the form inputs to change 082 */ 083 protected void _adaptFormValuesForChoiceList(Form form, Map<String, Object> formInputValues) 084 { 085 List<FormQuestion> choiceListQuestions = form.getQuestions() 086 .stream() 087 .filter(q -> q.getType() instanceof ChoicesListQuestionType) 088 .toList(); 089 090 for (FormQuestion question : choiceListQuestions) 091 { 092 ChoicesListQuestionType type = (ChoicesListQuestionType) question.getType(); 093 ChoiceSourceType sourceType = type.getSourceType(question); 094 095 String nameForForm = question.getNameForForm(); 096 if (formInputValues.containsKey(nameForForm)) 097 { 098 Object object = formInputValues.get(nameForForm); 099 Object newValue = sourceType.removeEmptyOrOtherValue(object); 100 if (newValue == null) 101 { 102 formInputValues.remove(nameForForm); 103 } 104 else 105 { 106 formInputValues.put(nameForForm, newValue); 107 } 108 109 } 110 } 111 } 112 113 /** 114 * Get a view without elements hidden by a rule 115 * @param form The current form 116 * @param entryView The entry view with possibly unwanted viewItems 117 * @param entryValues The entry values 118 * @param currentStepId current step of the entry. Can be empty if the form has no workflow 119 * @return a view with filtered items 120 */ 121 protected View _getRuleFilteredEntryView(Form form, View entryView, FormEntryValues entryValues, Optional<Long> currentStepId) 122 { 123 View filteredEntryView = new View(); 124 for (FormQuestion target : _getRuleFilteredQuestions(form, entryValues, currentStepId)) 125 { 126 ViewItem viewItem = entryView.getViewItem(target.getNameForForm()); 127 filteredEntryView.addViewItem(viewItem); 128 _manageOtherOption(entryView, filteredEntryView, target); 129 } 130 return filteredEntryView; 131 } 132 133 /** 134 * Get the list of active question depending of the form rules 135 * @param form the form 136 * @param entryValues the entry values to compute rules 137 * @param currentStepId the current step id. Can be empty if the form has no workflow 138 * @return the list of active question depending of the form rules 139 */ 140 protected abstract List<FormQuestion> _getRuleFilteredQuestions(Form form, FormEntryValues entryValues, Optional<Long> currentStepId); 141 142 private void _manageOtherOption(View entryView, View filteredEntryView, FormQuestion target) 143 { 144 if (target.getType() instanceof ChoicesListQuestionType type && type.hasOtherOption(target)) 145 { 146 ViewItem viewOtherItem = entryView.getViewItem(ChoicesListQuestionType.OTHER_PREFIX_DATA_NAME + target.getNameForForm()); 147 filteredEntryView.addViewItem(viewOtherItem); 148 } 149 } 150 151 /** 152 * Handle computed values 153 * @param questions the form questions 154 * @param entry the entry 155 * @param forEdition <code>true</code> to handle edition 156 */ 157 protected void _handleComputedValues(List<FormQuestion> questions, FormEntry entry, boolean forEdition) 158 { 159 for (FormQuestion question : questions) 160 { 161 FormQuestionType questionType = question.getType(); 162 if (questionType instanceof ComputedQuestionType type) 163 { 164 if (!forEdition || type.getComputingType(question).canEdit()) 165 { 166 Object computedValue = type.getComputingType(question).getComputedValue(question, entry); 167 if (computedValue != null) 168 { 169 entry.setValue(question.getNameForForm(), computedValue); 170 } 171 } 172 } 173 } 174 } 175}