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.question.types; 017 018import java.time.LocalDate; 019import java.time.ZonedDateTime; 020import java.util.List; 021import java.util.Map; 022 023import org.apache.commons.lang3.StringUtils; 024 025import org.ametys.core.util.DateUtils; 026import org.ametys.plugins.forms.helper.FormElementDefinitionHelper; 027import org.ametys.plugins.forms.question.validators.DateTimeIntervalFormValidator; 028import org.ametys.plugins.forms.question.validators.LocalDateIntervalFormValidator; 029import org.ametys.plugins.forms.repository.FormQuestion; 030import org.ametys.runtime.config.DisableCondition; 031import org.ametys.runtime.config.DisableCondition.OPERATOR; 032import org.ametys.runtime.config.DisableConditions; 033import org.ametys.runtime.i18n.I18nizableText; 034import org.ametys.runtime.model.ElementDefinition; 035import org.ametys.runtime.model.ModelItem; 036import org.ametys.runtime.model.SimpleViewItemGroup; 037import org.ametys.runtime.model.StaticEnumerator; 038import org.ametys.runtime.model.ViewElement; 039import org.ametys.runtime.model.type.ModelItemTypeConstants; 040import org.ametys.runtime.parameter.DefaultValidator; 041 042/** 043 * Class for creating date time questions 044 */ 045public class DateTimeQuestionType extends AbstractFormQuestionType 046{ 047 /** Constant for minimum Date attribute. */ 048 public static final String ATTRIBUTE_MIN_DATE = "min-date"; 049 050 /** Constant for maximum Date attribute. */ 051 public static final String ATTRIBUTE_MAX_DATE = "max-date"; 052 053 /** Constant for minimum Date attribute. */ 054 public static final String ATTRIBUTE_MIN_DATETIME = "min-datetime"; 055 056 /** Constant for maximum Date attribute. */ 057 public static final String ATTRIBUTE_MAX_DATETIME = "max-datetime"; 058 059 /** Constant for date format attribute. */ 060 public static final String ATTRIBUTE_DATE_FORMAT = "date-format"; 061 062 /** Name of datetimeStaticEnumerator entry that enable min and max datetime fields */ 063 public static final String DATE_TIME_FORMAT_VALUE = "datetime"; 064 065 /** Name of datetimeStaticEnumerator entry that enable min and max date fields */ 066 public static final String DATE_FORMAT_VALUE = "date"; 067 068 /** Constant for default title */ 069 public static final String DEFAULT_TITLE = "PLUGIN_FORMS_QUESTION_DEFAULT_TITLE_DATE"; 070 071 @Override 072 protected List<ModelItem> _getModelItems() 073 { 074 List<ModelItem> modelItems = super._getModelItems(); 075 076 // DATETIME Conditions 077 DisableConditions datetimeDisableConditions = new DisableConditions(); 078 DisableCondition conditionDatetime = new DisableCondition(ATTRIBUTE_DATE_FORMAT, OPERATOR.NEQ, DATE_TIME_FORMAT_VALUE); 079 datetimeDisableConditions.getConditions().add(conditionDatetime); 080 081 // MIN datetime 082 ElementDefinition minDateTime = FormElementDefinitionHelper.getElementDefinition(ATTRIBUTE_MIN_DATETIME, ModelItemTypeConstants.DATETIME_TYPE_ID, "PLUGINS_FORMS_QUESTIONS_DIALOG_DATETIME_MIN_DATE", "PLUGINS_FORMS_QUESTIONS_DIALOG_DATETIME_MIN_DATE_DESC", null); 083 minDateTime.setDisableConditions(datetimeDisableConditions); 084 modelItems.add(minDateTime); 085 086 // MAX datetime 087 ElementDefinition maxDateTime = FormElementDefinitionHelper.getElementDefinition(ATTRIBUTE_MAX_DATETIME, ModelItemTypeConstants.DATETIME_TYPE_ID, "PLUGINS_FORMS_QUESTIONS_DIALOG_DATETIME_MAX_DATE", "PLUGINS_FORMS_QUESTIONS_DIALOG_DATETIME_MAX_DATE_DESC", null); 088 maxDateTime.setDisableConditions(datetimeDisableConditions); 089 modelItems.add(maxDateTime); 090 091 // DATE Conditions 092 DisableConditions dateDisableConditions = new DisableConditions(); 093 DisableCondition conditionDate = new DisableCondition(ATTRIBUTE_DATE_FORMAT, OPERATOR.NEQ, DATE_FORMAT_VALUE); 094 dateDisableConditions.getConditions().add(conditionDate); 095 096 // MIN date 097 ElementDefinition minDate = FormElementDefinitionHelper.getElementDefinition(ATTRIBUTE_MIN_DATE, ModelItemTypeConstants.DATE_TYPE_ID, "PLUGINS_FORMS_QUESTIONS_DIALOG_DATETIME_MIN_DATE", "PLUGINS_FORMS_QUESTIONS_DIALOG_DATETIME_MIN_DATE_DESC", null); 098 minDate.setDisableConditions(dateDisableConditions); 099 modelItems.add(minDate); 100 101 // MAX date 102 ElementDefinition maxDate = FormElementDefinitionHelper.getElementDefinition(ATTRIBUTE_MAX_DATE, ModelItemTypeConstants.DATE_TYPE_ID, "PLUGINS_FORMS_QUESTIONS_DIALOG_DATETIME_MAX_DATE", "PLUGINS_FORMS_QUESTIONS_DIALOG_DATETIME_MAX_DATE_DESC", null); 103 maxDate.setDisableConditions(dateDisableConditions); 104 modelItems.add(maxDate); 105 106 // FORMAT 107 ElementDefinition<String> format = FormElementDefinitionHelper.getElementDefinition(ATTRIBUTE_DATE_FORMAT, ModelItemTypeConstants.STRING_TYPE_ID, "PLUGINS_FORMS_QUESTIONS_DIALOG_DATETIME_FORMAT", "PLUGINS_FORMS_QUESTIONS_DIALOG_DATETIME_FORMAT_DESC", new DefaultValidator(null, true)); 108 StaticEnumerator<String> datetimeStaticEnumerator = new StaticEnumerator<>(); 109 datetimeStaticEnumerator.add(new I18nizableText("plugin.forms", "PLUGINS_FORMS_QUESTIONS_DIALOG_DATETIME_FORMAT_DATETIME"), DATE_TIME_FORMAT_VALUE); 110 datetimeStaticEnumerator.add(new I18nizableText("plugin.forms", "PLUGINS_FORMS_QUESTIONS_DIALOG_DATETIME_FORMAT_DATE"), DATE_FORMAT_VALUE); 111 format.setEnumerator(datetimeStaticEnumerator); 112 format.setDefaultValue(DATE_FORMAT_VALUE); 113 modelItems.add(format); 114 115 return modelItems; 116 } 117 118 @Override 119 protected SimpleViewItemGroup _getMainTab() 120 { 121 SimpleViewItemGroup mainFieldset = super._getMainTab(); 122 123 ViewElement format = new ViewElement(); 124 format.setDefinition((ElementDefinition< ? >) getModel().getModelItem(ATTRIBUTE_DATE_FORMAT)); 125 mainFieldset.addViewItem(format); 126 127 return mainFieldset; 128 } 129 130 @Override 131 protected SimpleViewItemGroup _getAdvancedTab() 132 { 133 SimpleViewItemGroup advancedFieldset = super._getAdvancedTab(); 134 135 ViewElement minDate = new ViewElement(); 136 minDate.setDefinition((ElementDefinition< ? >) getModel().getModelItem(ATTRIBUTE_MIN_DATE)); 137 advancedFieldset.addViewItem(minDate); 138 139 ViewElement maxDate = new ViewElement(); 140 maxDate.setDefinition((ElementDefinition< ? >) getModel().getModelItem(ATTRIBUTE_MAX_DATE)); 141 advancedFieldset.addViewItem(maxDate); 142 143 ViewElement minDateTime = new ViewElement(); 144 minDateTime.setDefinition((ElementDefinition< ? >) getModel().getModelItem(ATTRIBUTE_MIN_DATETIME)); 145 advancedFieldset.addViewItem(minDateTime); 146 147 ViewElement maxDateTime = new ViewElement(); 148 maxDateTime.setDefinition((ElementDefinition< ? >) getModel().getModelItem(ATTRIBUTE_MAX_DATETIME)); 149 advancedFieldset.addViewItem(maxDateTime); 150 151 return advancedFieldset; 152 } 153 154 public String getStorageType(FormQuestion question) 155 { 156 String type = question.getValue(ATTRIBUTE_DATE_FORMAT); 157 return DATE_TIME_FORMAT_VALUE.equals(type) ? ModelItemTypeConstants.DATETIME_TYPE_ID : ModelItemTypeConstants.DATE_TYPE_ID; 158 } 159 160 @Override 161 protected ModelItem _getEntryModelItem(FormQuestion question) 162 { 163 ModelItem item = super._getEntryModelItem(question); 164 if (DATE_TIME_FORMAT_VALUE.equals(question.getValue(ATTRIBUTE_DATE_FORMAT))) 165 { 166 ZonedDateTime minDate = question.getValue(ATTRIBUTE_MIN_DATETIME); 167 ZonedDateTime maxDate = question.getValue(ATTRIBUTE_MAX_DATETIME); 168 ((ElementDefinition) item).setValidator(new DateTimeIntervalFormValidator(null, isMandatory(question), minDate, maxDate)); 169 } 170 else 171 { 172 LocalDate minDate = question.getValue(ATTRIBUTE_MIN_DATE); 173 LocalDate maxDate = question.getValue(ATTRIBUTE_MAX_DATE); 174 ((ElementDefinition) item).setValidator(new LocalDateIntervalFormValidator(null, isMandatory(question), minDate, maxDate)); 175 } 176 return item; 177 } 178 179 @Override 180 public void validateQuestionValues(Map<String, Object> values, Map<String, I18nizableText> errors) 181 { 182 super.validateQuestionValues(values, errors); 183 184 String format = (String) values.get(ATTRIBUTE_DATE_FORMAT); 185 switch (format) 186 { 187 case DATE_FORMAT_VALUE: 188 String minDateAsString = (String) values.getOrDefault(ATTRIBUTE_MIN_DATE, null); 189 String maxDateAsString = (String) values.getOrDefault(ATTRIBUTE_MAX_DATE, null); 190 if (StringUtils.isNotBlank(minDateAsString) && StringUtils.isNotBlank(maxDateAsString)) 191 { 192 LocalDate minDate = LocalDate.parse(minDateAsString); 193 LocalDate maxDate = LocalDate.parse(maxDateAsString); 194 195 if (minDate != null && maxDate != null && minDate.isAfter(maxDate)) 196 { 197 errors.put(ATTRIBUTE_MIN_DATE, new I18nizableText("plugin.forms", "PLUGINS_FORMS_QUESTIONS_DIALOG_DATE_GAP_ERROR")); 198 errors.put(ATTRIBUTE_MAX_DATE, new I18nizableText("plugin.forms", "PLUGINS_FORMS_QUESTIONS_DIALOG_DATE_GAP_ERROR")); 199 } 200 } 201 break; 202 case DATE_TIME_FORMAT_VALUE: 203 String minDateTimeAsString = (String) values.getOrDefault(ATTRIBUTE_MIN_DATETIME, null); 204 String maxDateTimeAsString = (String) values.getOrDefault(ATTRIBUTE_MAX_DATETIME, null); 205 if (StringUtils.isNotBlank(minDateTimeAsString) && StringUtils.isNotBlank(maxDateTimeAsString)) 206 { 207 ZonedDateTime minDateTime = DateUtils.parseZonedDateTime(minDateTimeAsString); 208 ZonedDateTime maxDateTime = DateUtils.parseZonedDateTime(maxDateTimeAsString); 209 if (minDateTime.isAfter(maxDateTime)) 210 { 211 errors.put(ATTRIBUTE_MIN_DATETIME, new I18nizableText("plugin.forms", "PLUGINS_FORMS_QUESTIONS_DIALOG_DATE_GAP_ERROR")); 212 errors.put(ATTRIBUTE_MAX_DATETIME, new I18nizableText("plugin.forms", "PLUGINS_FORMS_QUESTIONS_DIALOG_DATE_GAP_ERROR")); 213 } 214 } 215 break; 216 default: 217 getLogger().error("Date format " + format + " is not supported"); 218 break; 219 } 220 } 221 222 public I18nizableText getDefaultTitle() 223 { 224 return new I18nizableText("plugin.forms", DEFAULT_TITLE); 225 } 226 227 @Override 228 public List<String> getFieldToDisableIfFormPublished(FormQuestion question) 229 { 230 List<String> fieldNames = super.getFieldToDisableIfFormPublished(question); 231 fieldNames.add(ATTRIBUTE_DATE_FORMAT); 232 return fieldNames; 233 } 234}