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.calendar.search; 017 018import java.time.ZonedDateTime; 019import java.util.Arrays; 020import java.util.List; 021import java.util.Map; 022import java.util.Map.Entry; 023 024import org.apache.avalon.framework.parameters.ParameterException; 025import org.apache.avalon.framework.parameters.Parameters; 026import org.apache.cocoon.components.ContextHelper; 027import org.apache.cocoon.xml.AttributesImpl; 028import org.apache.cocoon.xml.XMLUtils; 029import org.apache.commons.lang3.StringUtils; 030import org.xml.sax.ContentHandler; 031import org.xml.sax.SAXException; 032 033import org.ametys.cms.tag.ColorableTag; 034import org.ametys.cms.tag.Tag; 035import org.ametys.core.util.DateUtils; 036import org.ametys.core.util.URIUtils; 037import org.ametys.plugins.calendar.events.EventsFilterHelper.DateTimeRange; 038import org.ametys.web.frontoffice.search.SearchService; 039import org.ametys.web.frontoffice.search.instance.SearchServiceInstance; 040import org.ametys.web.frontoffice.search.instance.model.RightCheckingMode; 041import org.ametys.web.frontoffice.search.metamodel.AdditionalParameterValueMap; 042import org.ametys.web.frontoffice.search.requesttime.SearchComponentArguments; 043import org.ametys.web.repository.page.Page; 044import org.ametys.web.repository.page.ZoneItem; 045 046/** 047 * Calendar search service 048 * 049 */ 050public class CalendarSearchService extends SearchService 051{ 052 /** Id of service */ 053 public static final String SERVICE_ID = "org.ametys.plugins.calendar.SearchEvents"; 054 055 /** Parameter to enable calendar search components */ 056 public static final String ENABLE_CALENDAR_PARAMETER_NAME = "calendar"; 057 058 /** Service parameter for tags' categories */ 059 public static final String SERVICE_PARAM_TAG_CATEGORIES = "tag-categories"; 060 061 /** Service parameter for contents' view */ 062 public static final String SERVICE_PARAM_CONTENT_VIEW = "calendarContentView"; 063 064 /** Service parameter for calendar content types */ 065 public static final String SERVICE_PARAM_CONTENT_TYPES = "calendarContentTypes"; 066 067 /** Parameter for start date */ 068 public static final String PARAM_START_DATE = "start"; 069 070 /** Parameter for end date */ 071 public static final String PARAM_END_DATE = "end"; 072 073 /** Parameter for selected tags */ 074 public static final String PARAM_TAGS = "tags"; 075 076 /** Parameter for selected tags */ 077 public static final String PARAM_SUBMIT = "submit-form"; 078 079 /** Attribute name for content's start date */ 080 public static final String START_DATE_ATTRIBUTE_NAME = "start-date"; 081 082 /** Attribute name for content's end date */ 083 public static final String END_DATE_ATTRIBUTE_NAME = "end-date"; 084 085 private static final String __TAGS_ALL_VALUE = "_ALL"; 086 087 @Override 088 public boolean isCacheable(Page currentPage, ZoneItem zoneItem) 089 { 090 boolean isDebug = _isDebug(ContextHelper.getRequest(_context), _renderingContextHandler); 091 SearchServiceInstance serviceInstance = _searchServiceInstanceManager.get(zoneItem.getId()); 092 093 if (!isDebug) 094 { 095 // Cacheable if no user input and right checking mode is on 'FAST' 096 return !_hasUserInput(serviceInstance) && serviceInstance.getRightCheckingMode() == RightCheckingMode.FAST && !hasTagCategories(serviceInstance); 097 } 098 099 return false; 100 } 101 102 /** 103 * Determines if tags' categories filter is active 104 * @param serviceInstance the service instance 105 * @return true if tags' categories filter is active 106 */ 107 public static boolean hasTagCategories(SearchServiceInstance serviceInstance) 108 { 109 List<String> categoryNames = getTagCategories(serviceInstance); 110 return categoryNames != null && !categoryNames.isEmpty(); 111 } 112 113 /** 114 * Get the tags' category 115 * @param serviceInstance the service instance 116 * @return the tags' category. Can be null if no tags' categories are configured 117 */ 118 public static List<String> getTagCategories(SearchServiceInstance serviceInstance) 119 { 120 AdditionalParameterValueMap additionalParameterValues = serviceInstance.getAdditionalParameterValues(); 121 return additionalParameterValues.getValue(SERVICE_PARAM_TAG_CATEGORIES); 122 } 123 124 /** 125 * Get the active tags 126 * @param args the search arguments 127 * @return the active tags 128 */ 129 public static List<String> getSelectedTags(SearchComponentArguments args) 130 { 131 String parameter = args.generatorParameters().getParameter(PARAM_TAGS, ""); 132 if (__TAGS_ALL_VALUE.equals(parameter)) 133 { 134 return List.of(); 135 } 136 String[] selectedTags = StringUtils.isNotEmpty(parameter) ? parameter.split(",") : new String[0]; 137 return Arrays.asList(selectedTags); 138 } 139 140 /** 141 * Determines if is calendar service 142 * @param args the search component arguments 143 * @return true if it is calendar service 144 */ 145 public static boolean isActive(SearchComponentArguments args) 146 { 147 return args.generatorParameters().getParameterAsBoolean(ENABLE_CALENDAR_PARAMETER_NAME, false); 148 } 149 150 /** 151 * Determines if form is submit to get results 152 * @param args the search component arguments 153 * @return true if form is submit 154 */ 155 public static boolean isFormSubmit(SearchComponentArguments args) 156 { 157 return args.generatorParameters().getParameterAsBoolean(PARAM_SUBMIT, false); 158 } 159 160 /** 161 * Get search date range 162 * @param args the search component arguments 163 * @return the date time range 164 */ 165 public static DateTimeRange getDateRange(SearchComponentArguments args) 166 { 167 Parameters parameters = args.generatorParameters(); 168 if (parameters.isParameter(PARAM_START_DATE) && parameters.isParameter(PARAM_END_DATE)) 169 { 170 try 171 { 172 String start = URIUtils.decode(parameters.getParameter(CalendarSearchService.PARAM_START_DATE)); 173 String end = URIUtils.decode(parameters.getParameter(CalendarSearchService.PARAM_END_DATE)); 174 175 ZonedDateTime fromDateTime = DateUtils.parseZonedDateTime(start); 176 ZonedDateTime untilDateTime = DateUtils.parseZonedDateTime(end); 177 178 return new DateTimeRange(fromDateTime, untilDateTime); 179 } 180 catch (ParameterException e) 181 { 182 // ignore 183 } 184 } 185 186 return null; 187 } 188 189 /** 190 * SAX a tag 191 * @param handler the content handler 192 * @param tag the tag 193 * @throws SAXException if an error occurred 194 */ 195 public static void saxTag(ContentHandler handler, Tag tag) throws SAXException 196 { 197 saxTag(handler, new AttributesImpl(), tag); 198 } 199 200 /** 201 * SAX a tag 202 * @param handler the content handler 203 * @param attrs The attributes 204 * @param tag the tag 205 * @throws SAXException if an error occurred 206 */ 207 public static void saxTag(ContentHandler handler, AttributesImpl attrs, Tag tag) throws SAXException 208 { 209 if (tag != null) 210 { 211 attrs.addCDATAAttribute("name", tag.getName()); 212 XMLUtils.startElement(handler, "tag", attrs); 213 214 XMLUtils.startElement(handler, "label"); 215 tag.getTitle().toSAX(handler); 216 XMLUtils.endElement(handler, "label"); 217 218 saxTagColor(handler, tag); 219 220 XMLUtils.endElement(handler, "tag"); 221 } 222 } 223 224 /** 225 * SAX the color of a tag 226 * @param handler the content handler 227 * @param tag the tag 228 * @throws SAXException if an error occurred 229 */ 230 public static void saxTagColor(ContentHandler handler, Tag tag) throws SAXException 231 { 232 if (tag instanceof ColorableTag) 233 { 234 String colorIndex = ((ColorableTag) tag).getColor(true); 235 Map<String, String> colors = ((ColorableTag) tag).getColorComponent().getColors().get(colorIndex); 236 if (colors != null) 237 { 238 XMLUtils.startElement(handler, "color"); 239 for (Entry<String, String> entry : colors.entrySet()) 240 { 241 XMLUtils.createElement(handler, entry.getKey(), entry.getValue()); 242 } 243 XMLUtils.endElement(handler, "color"); 244 } 245 } 246 } 247}