001/* 002 * Copyright 2022 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.helper; 017 018import java.util.ArrayList; 019import java.util.HashMap; 020import java.util.List; 021import java.util.Map; 022import java.util.stream.Collectors; 023 024import org.apache.avalon.framework.component.Component; 025import org.apache.avalon.framework.service.ServiceException; 026import org.apache.avalon.framework.service.ServiceManager; 027import org.apache.avalon.framework.service.Serviceable; 028 029import org.ametys.core.ui.Callable; 030import org.ametys.plugins.forms.question.FormQuestionType; 031import org.ametys.plugins.forms.question.sources.ChoiceSourceType; 032import org.ametys.plugins.forms.question.types.CheckBoxQuestionType; 033import org.ametys.plugins.forms.question.types.ChoicesListQuestionType; 034import org.ametys.plugins.forms.repository.Form; 035import org.ametys.plugins.forms.repository.FormQuestion; 036import org.ametys.plugins.forms.repository.type.Rule.QuestionRuleType; 037import org.ametys.plugins.repository.AmetysObjectResolver; 038import org.ametys.runtime.i18n.I18nizableText; 039 040/** 041 * Helper for getting rules properties 042 */ 043public class QuestionRuleHelper implements Serviceable, Component 044{ 045 /** The Ametys object resolver */ 046 protected AmetysObjectResolver _resolver; 047 048 public void service(ServiceManager manager) throws ServiceException 049 { 050 _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE); 051 } 052 053 /** 054 * Get all choices list and booleans questions as source for the rule 055 * @param formId id of the current form 056 * @param questionId id of the current question 057 * @return a map containing the list of questions 058 */ 059 @Callable 060 public Map<String, Object> getSourceQuestions(String formId, String questionId) 061 { 062 Map<String, Object> results = new HashMap<>(); 063 Form form = _resolver.resolveById(formId); 064 List<FormQuestion> questions = form.getQuestions() 065 .stream() 066 .filter(question -> this._isChoiceListWithNoTooManyOptions(question) || question.getType() instanceof CheckBoxQuestionType) // Question must be a choice list with not too many options 067 .filter(question -> !question.isModifiable()) // Question must be not modifiable 068 .filter(question -> !question.getId().equals(questionId)) // Remove the given question from the list 069 .collect(Collectors.toList()); 070 List<Object> sources = new ArrayList<>(); 071 for (FormQuestion question : questions) 072 { 073 Map<String, String> properties = new HashMap<>(); 074 properties.put("label", question.getTitle()); 075 properties.put("id", question.getId()); 076 sources.add(properties); 077 } 078 results.put("data", sources); 079 080 return results; 081 } 082 083 private boolean _isChoiceListWithNoTooManyOptions(FormQuestion question) 084 { 085 FormQuestionType type = question.getType(); 086 if (type instanceof ChoicesListQuestionType cLType) 087 { 088 ChoiceSourceType sourceType = cLType.getSourceType(question); 089 return !sourceType.remoteData(); 090 } 091 092 return false; 093 } 094 095 /** 096 * Get all the available options for the selected question 097 * @param questionId id of the selected question 098 * @return a map containing the list of all the options as map (label for display and unique value) 099 */ 100 @Callable 101 public Map<String, Object> getSourceOptions(String questionId) 102 { 103 Map<String, Object> results = new HashMap<>(); 104 FormQuestion formQuestion = _resolver.resolveById(questionId); 105 List<Object> options = new ArrayList<>(); 106 if (formQuestion.getType() instanceof ChoicesListQuestionType type && !type.getSourceType(formQuestion).remoteData()) 107 { 108 Map<String, I18nizableText> choices = type.getOptions(formQuestion); 109 for (String optionValue : choices.keySet()) 110 { 111 Map<String, Object> choicesToJson = new HashMap<>(); 112 choicesToJson.put("label", choices.get(optionValue)); 113 choicesToJson.put("value", optionValue); 114 options.add(choicesToJson); 115 } 116 if (type.hasOtherOption(formQuestion)) 117 { 118 Map<String, Object> choicesToJson = new HashMap<>(); 119 choicesToJson.put("label", new I18nizableText("plugin.forms", "PLUGINS_FORMS_DISPLAY_OTHER_OPTION_COMBOBOX")); 120 choicesToJson.put("value", ChoicesListQuestionType.OTHER_OPTION_VALUE); 121 options.add(choicesToJson); 122 } 123 } 124 else 125 { 126 options.add(Map.of( 127 "label", new I18nizableText("plugin.forms", "PLUGINS_FORMS_QUESTION_RULES_OPTION_CHECKED"), 128 "value", "true" 129 )); 130 131 options.add(Map.of( 132 "label", new I18nizableText("plugin.forms", "PLUGINS_FORMS_QUESTION_RULES_OPTION_UNCHECKED"), 133 "value", "false" 134 )); 135 } 136 results.put("data", options); 137 return results; 138 } 139 140 /** 141 * Get the actions available to apply to this question 142 * @return a list of actions (currently hide or show) 143 */ 144 @Callable 145 public Map<String, Object> getRuleActions() 146 { 147 Map<String, Object> results = new HashMap<>(); 148 149 List<Object> actions = new ArrayList<>(); 150 151 actions.add(Map.of( 152 "label", QuestionRuleType.HIDE.getLabel(), 153 "value", QuestionRuleType.HIDE.name() 154 )); 155 156 actions.add(Map.of( 157 "label", QuestionRuleType.SHOW.getLabel(), 158 "value", QuestionRuleType.SHOW.name() 159 )); 160 161 results.put("data", actions); 162 return results; 163 } 164}