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.cms.search.ui.model.impl; 017 018import java.util.LinkedHashMap; 019import java.util.List; 020import java.util.Map; 021 022import org.apache.commons.collections.MapUtils; 023 024import org.ametys.cms.search.model.DefaultSearchModel; 025import org.ametys.cms.search.model.LanguageAwareCriterionDefinition; 026import org.ametys.cms.search.model.SearchModelCriterionDefinition; 027import org.ametys.cms.search.model.SearchModelCriterionDefinitionHelper; 028import org.ametys.cms.search.ui.model.SearchModelCriterionViewItem; 029import org.ametys.cms.search.ui.model.SearchUIModel; 030import org.ametys.runtime.model.DefinitionContext; 031import org.ametys.runtime.model.ElementDefinition; 032import org.ametys.runtime.model.ModelViewItem; 033import org.ametys.runtime.model.View; 034import org.ametys.runtime.model.ViewHelper; 035import org.ametys.runtime.model.ViewItem; 036import org.ametys.runtime.model.ViewItemAccessor; 037import org.ametys.runtime.model.ViewItemContainer; 038 039/** 040 * Default implementation of a {@link SearchUIModel}. 041 */ 042public class DefaultSearchUIModel extends DefaultSearchModel implements SearchUIModel 043{ 044 /** The default plugin name for URLs */ 045 protected static final String __DEFAULT_URL_PLUGIN = "cms"; 046 /** The default URL for search */ 047 protected static final String __DEFAULT_SEARCH_URL = "search/list.json"; 048 /** The default URL for CSV export */ 049 protected static final String __DEFAULT_EXPORT_CSV_URL = "search/export.csv"; 050 /** The default URL for DOC export */ 051 protected static final String __DEFAULT_EXPORT_DOC_URL = "search/export.doc"; 052 /** The default URL for XML export */ 053 protected static final String __DEFAULT_EXPORT_XML_URL = "search/export.xml"; 054 /** The default URL for PDF export */ 055 protected static final String __DEFAULT_EXPORT_PDF_URL = null; 056 /** The URL for print results */ 057 protected static final String __DEFAULT_PRINT_URL = "search/print.html"; 058 059 /** The advanced criteria */ 060 private ViewItemContainer _advancedCriteria = new View(); 061 062 /** The page size **/ 063 private int _pageSize = -1; 064 065 /** The URL for search */ 066 private String _searchUrl = __DEFAULT_SEARCH_URL; 067 /** The plugin name for search */ 068 private String _searchUrlPlugin = __DEFAULT_URL_PLUGIN; 069 070 /** The URL for CSV export of results */ 071 private String _exportCSVUrl = __DEFAULT_EXPORT_CSV_URL; 072 /** The plugin name for CSV export of results */ 073 private String _exportCSVUrlPlugin = __DEFAULT_URL_PLUGIN; 074 /** The URL for doc export of results */ 075 private String _exportDOCUrl = __DEFAULT_EXPORT_DOC_URL; 076 /** The plugin name for doc export of results */ 077 private String _exportDOCUrlPlugin = __DEFAULT_URL_PLUGIN; 078 /** The URL for XML export of results */ 079 private String _exportXMLUrl = __DEFAULT_EXPORT_XML_URL; 080 /** The plugin name for XML export of results */ 081 private String _exportXMLUrlPlugin = __DEFAULT_URL_PLUGIN; 082 /** The URL for PDF export of results */ 083 private String _exportPDFUrl = __DEFAULT_EXPORT_PDF_URL; 084 /** The plugin name for PDF export of results */ 085 private String _exportPDFUrlPlugin = __DEFAULT_URL_PLUGIN; 086 087 /** The URL for print results */ 088 private String _printUrl = __DEFAULT_PRINT_URL; 089 /** The plugin name for print results */ 090 private String _printUrlPlugin = __DEFAULT_URL_PLUGIN; 091 092 /** The name of the view to use for summary of the content */ 093 private String _summaryView; 094 095 /** Determine is sort is allowed on multiple join */ 096 private boolean _sortOnMultipleJoin; 097 098 /** 099 * Default constructor 100 */ 101 public DefaultSearchUIModel() 102 { 103 super(); 104 } 105 106 /** 107 * Constructor by copying an existing {@link SearchUIModel}. 108 * @param searchUIModelToCopy The {@link SearchUIModel} to copy 109 * @param contextualParameters The contextual parameters 110 */ 111 public DefaultSearchUIModel(SearchUIModel searchUIModelToCopy, Map<String, Object> contextualParameters) 112 { 113 super(searchUIModelToCopy, contextualParameters); 114 115 View advancedCriteria = new View(); 116 ViewItemContainer advancedCriteriaToCopy = searchUIModelToCopy.getAdvancedCriteria(contextualParameters); 117 List<ViewItem> advancedCriteriaViewItems = ViewHelper.copyViewItems(advancedCriteriaToCopy.getViewItems()); 118 advancedCriteria.addViewItems(advancedCriteriaViewItems); 119 setAdvancedCriteria(advancedCriteria); 120 121 setPageSize(searchUIModelToCopy.getPageSize(contextualParameters)); 122 123 setSearchUrl(searchUIModelToCopy.getSearchUrl(contextualParameters)); 124 setSearchUrlPlugin(searchUIModelToCopy.getSearchUrlPlugin(contextualParameters)); 125 126 setExportCSVUrl(searchUIModelToCopy.getExportCSVUrl(contextualParameters)); 127 setExportCSVUrlPlugin(searchUIModelToCopy.getExportCSVUrlPlugin(contextualParameters)); 128 setExportDOCUrl(searchUIModelToCopy.getExportDOCUrl(contextualParameters)); 129 setExportDOCUrlPlugin(searchUIModelToCopy.getExportDOCUrlPlugin(contextualParameters)); 130 setExportXMLUrl(searchUIModelToCopy.getExportXMLUrl(contextualParameters)); 131 setExportXMLUrlPlugin(searchUIModelToCopy.getExportXMLUrlPlugin(contextualParameters)); 132 setExportPDFUrl(searchUIModelToCopy.getExportPDFUrl(contextualParameters)); 133 setExportPDFUrlPlugin(searchUIModelToCopy.getExportPDFUrlPlugin(contextualParameters)); 134 135 setPrintUrl(searchUIModelToCopy.getPrintUrl(contextualParameters)); 136 setPrintUrlPlugin(searchUIModelToCopy.getPrintUrlPlugin(contextualParameters)); 137 } 138 139 public ViewItemContainer getAdvancedCriteria(Map<String, Object> contextualParameters) 140 { 141 return _advancedCriteria; 142 } 143 144 /** 145 * Add criteria to the advanced criteria. The created criteria reference the given paths 146 * @param criterionDefinitionHelper the criterion definition helper 147 * @param contextualParameters the contextual parameters 148 * @param references the paths to the items the criteria will reference 149 */ 150 public void addAdvancedCriteria(SearchModelCriterionDefinitionHelper criterionDefinitionHelper, Map<String, Object> contextualParameters, String... references) 151 { 152 for (String reference : references) 153 { 154 SearchModelCriterionDefinition criterion = criterionDefinitionHelper.createReferencingCriterionDefinition(this, reference, getContentTypes(contextualParameters)); 155 addAdvancedCriterion(criterion, contextualParameters); 156 } 157 } 158 159 /** 160 * Set the advanced criteria 161 * @param criteria The advanced criteria to set 162 */ 163 public void setAdvancedCriteria(ViewItemContainer criteria) 164 { 165 _advancedCriteria = criteria; 166 } 167 168 public int getPageSize(Map<String, Object> contextualParameters) 169 { 170 return _pageSize; 171 } 172 173 /** 174 * Set the page size 175 * @param pageSize The page size to set. Set to negative or 0 for unlimited or default 176 */ 177 public void setPageSize(int pageSize) 178 { 179 _pageSize = pageSize; 180 } 181 182 public String getSearchUrl(Map<String, Object> contextualParameters) 183 { 184 return _searchUrl; 185 } 186 187 /** 188 * Set the URL for search 189 * @param searchUrl The URL to set 190 */ 191 public void setSearchUrl(String searchUrl) 192 { 193 _searchUrl = searchUrl; 194 } 195 196 public String getSearchUrlPlugin(Map<String, Object> contextualParameters) 197 { 198 return _searchUrlPlugin; 199 } 200 201 /** 202 * Set the plugin name for search 203 * @param searchUrlPlugin the plugin name to set 204 */ 205 public void setSearchUrlPlugin(String searchUrlPlugin) 206 { 207 _searchUrlPlugin = searchUrlPlugin; 208 } 209 210 public String getExportCSVUrl(Map<String, Object> contextualParameters) 211 { 212 return _exportCSVUrl; 213 } 214 215 /** 216 * Set the URL for CSV export of results 217 * @param exportCSVUrl The URL to set 218 */ 219 public void setExportCSVUrl(String exportCSVUrl) 220 { 221 _exportCSVUrl = exportCSVUrl; 222 } 223 224 public String getExportCSVUrlPlugin(Map<String, Object> contextualParameters) 225 { 226 return _exportCSVUrlPlugin; 227 } 228 229 /** 230 * Set the plugin name for CSV export of results 231 * @param exportCSVUrlPlugin the plugin name to set 232 */ 233 public void setExportCSVUrlPlugin(String exportCSVUrlPlugin) 234 { 235 _exportCSVUrlPlugin = exportCSVUrlPlugin; 236 } 237 238 public String getExportDOCUrl(Map<String, Object> contextualParameters) 239 { 240 return _exportDOCUrl; 241 } 242 243 /** 244 * Set the URL for Doc export of results 245 * @param exportDOCUrl The URL to set 246 */ 247 public void setExportDOCUrl(String exportDOCUrl) 248 { 249 _exportDOCUrl = exportDOCUrl; 250 } 251 252 public String getExportDOCUrlPlugin(Map<String, Object> contextualParameters) 253 { 254 return _exportDOCUrlPlugin; 255 } 256 257 /** 258 * Set the plugin name for Doc export of results 259 * @param exportDOCUrlPlugin the plugin name to set 260 */ 261 public void setExportDOCUrlPlugin(String exportDOCUrlPlugin) 262 { 263 _exportDOCUrlPlugin = exportDOCUrlPlugin; 264 } 265 266 public String getExportXMLUrl(Map<String, Object> contextualParameters) 267 { 268 return _exportXMLUrl; 269 } 270 271 /** 272 * Set the URL for XML export of results 273 * @param exportXMLUrl The URL to set 274 */ 275 public void setExportXMLUrl(String exportXMLUrl) 276 { 277 _exportXMLUrl = exportXMLUrl; 278 } 279 280 public String getExportXMLUrlPlugin(Map<String, Object> contextualParameters) 281 { 282 return _exportXMLUrlPlugin; 283 } 284 285 /** 286 * Set the plugin name for XML export of results 287 * @param exportXMLUrlPlugin the plugin name to set 288 */ 289 public void setExportXMLUrlPlugin(String exportXMLUrlPlugin) 290 { 291 _exportXMLUrlPlugin = exportXMLUrlPlugin; 292 } 293 294 public String getExportPDFUrl(Map<String, Object> contextualParameters) 295 { 296 return _exportPDFUrl; 297 } 298 299 /** 300 * Set the URL for PDF export of results 301 * @param exportPDFUrl The URL to set 302 */ 303 public void setExportPDFUrl(String exportPDFUrl) 304 { 305 _exportPDFUrl = exportPDFUrl; 306 } 307 308 public String getExportPDFUrlPlugin(Map<String, Object> contextualParameters) 309 { 310 return _exportPDFUrlPlugin; 311 } 312 313 /** 314 * Set the plugin name for PDF export of results 315 * @param exportPDFUrlPlugin the plugin name to set 316 */ 317 public void setExportPDFUrlPlugin(String exportPDFUrlPlugin) 318 { 319 _exportPDFUrlPlugin = exportPDFUrlPlugin; 320 } 321 322 public String getPrintUrl(Map<String, Object> contextualParameters) 323 { 324 return _printUrl; 325 } 326 327 /** 328 * Set the URL for print results 329 * @param printUrl The URL to set 330 */ 331 public void setPrintUrl(String printUrl) 332 { 333 _printUrl = printUrl; 334 } 335 336 public String getPrintUrlPlugin(Map<String, Object> contextualParameters) 337 { 338 return _printUrlPlugin; 339 } 340 341 /** 342 * Set the plugin name for print results 343 * @param printUrlPlugin the plugin name to set 344 */ 345 public void setPrintUrlPlugin(String printUrlPlugin) 346 { 347 _printUrlPlugin = printUrlPlugin; 348 } 349 350 public String getSummaryView() 351 { 352 return _summaryView; 353 } 354 355 /** 356 * Set The name of the view to use for summary of the content 357 * @param summaryView the name to set 358 */ 359 public void setSummaryView(String summaryView) 360 { 361 _summaryView = summaryView; 362 } 363 364 /** 365 * Indicates if sorting on join columns which contain at least one {@link ElementDefinition#isMultiple() multiple} {@link ElementDefinition definition} in its path (intermediate ones only) must be allowed. 366 * <br>If the final definition of the path is multiple, the column will not be sortable though. 367 * @return <code>true</code> if sorting on join columns which contains at least one multiple item in its path (intermediate ones only) must be allowed. 368 */ 369 protected boolean allowSortOnMultipleJoin() 370 { 371 return _sortOnMultipleJoin; 372 } 373 374 /** 375 * Set to <code>true</code> to allow sort on multiple join (default to <code>false</code>) 376 * @param sortOnMultipleJoin <code>true</code> to allow sort on multiple join, <code>false</code> otherwise 377 */ 378 public void setAllowSortOnMultipleJoin(boolean sortOnMultipleJoin) 379 { 380 _sortOnMultipleJoin = sortOnMultipleJoin; 381 } 382 383 @Override 384 public Map<String, Object> toJSON(Map<String, Object> contextualParameters) 385 { 386 Map<String, Object> jsonObject = super.toJSON(contextualParameters); 387 388 jsonObject.put("pageSize", getPageSize(contextualParameters)); 389 jsonObject.put("workspace", getWorkspace(contextualParameters)); 390 jsonObject.put("searchUrl", getSearchUrl(contextualParameters)); 391 jsonObject.put("searchUrlPlugin", getSearchUrlPlugin(contextualParameters)); 392 jsonObject.put("exportCSVUrl", getExportCSVUrl(contextualParameters)); 393 jsonObject.put("exportCSVUrlPlugin", getExportCSVUrlPlugin(contextualParameters)); 394 jsonObject.put("exportDOCUrl", getExportDOCUrl(contextualParameters)); 395 jsonObject.put("exportDOCUrlPlugin", getExportDOCUrlPlugin(contextualParameters)); 396 jsonObject.put("exportXMLUrl", getExportXMLUrl(contextualParameters)); 397 jsonObject.put("exportXMLUrlPlugin", getExportXMLUrlPlugin(contextualParameters)); 398 jsonObject.put("exportPDFUrl", getExportPDFUrl(contextualParameters)); 399 jsonObject.put("exportPDFUrlPlugin", getExportPDFUrlPlugin(contextualParameters)); 400 jsonObject.put("printUrl", getPrintUrl(contextualParameters)); 401 jsonObject.put("printUrlPlugin", getPrintUrlPlugin(contextualParameters)); 402 jsonObject.put("summaryView", getSummaryView()); 403 404 jsonObject.put("advanced-criteria", _getAdvancedCriteriaListInfo(getAdvancedCriteria(contextualParameters))); 405 406 return jsonObject; 407 } 408 409 /** 410 * Return information on a list of advanced {@link SearchModelCriterionViewItem}, serialized as a Map. 411 * @param criteria A map of advanced criteria. 412 * @return the detailed information serialized in a Map. 413 */ 414 protected Map<String, Object> _getAdvancedCriteriaListInfo(ViewItemAccessor criteria) 415 { 416 Map<String, Object> jsonObject = new LinkedHashMap<>(); 417 418 // Make a copy of the criteria view 419 ViewItemAccessor criteriaCopy = new View(); 420 criteriaCopy.addViewItems(ViewHelper.copyViewItems(criteria.getViewItems())); 421 422 // Extract language criterion from the others 423 ModelViewItem languageCriterion = _getContentLanguageCriterionViewItem(criteriaCopy); 424 if (languageCriterion != null) 425 { 426 jsonObject.put("language", languageCriterion.toJSON(DefinitionContext.newInstance())); 427 428 // Remove language criterion that is already processed 429 ViewItemAccessor languageParent = languageCriterion.getParent(); 430 languageParent.removeViewItem(languageCriterion); 431 } 432 433 Map<String, Object> criteriaObject = ViewHelper.viewItemsToJSON(criteriaCopy.getViewItems(), DefinitionContext.newInstance()); 434 if (MapUtils.isNotEmpty(criteriaObject)) 435 { 436 jsonObject.put("criteria", criteriaObject); 437 } 438 439 return jsonObject; 440 } 441 442 private ModelViewItem _getContentLanguageCriterionViewItem(ViewItemAccessor criteria) 443 { 444 for (ViewItem viewItem : criteria.getViewItems()) 445 { 446 if (viewItem instanceof SearchModelCriterionViewItem criterionViewItem 447 && criterionViewItem.getDefinition() instanceof LanguageAwareCriterionDefinition) 448 { 449 return criterionViewItem; 450 } 451 else if (viewItem instanceof ViewItemContainer itemContainer) 452 { 453 ModelViewItem contentLanguageCriterion = _getContentLanguageCriterionViewItem(itemContainer); 454 if (contentLanguageCriterion != null) 455 { 456 return contentLanguageCriterion; 457 } 458 } 459 } 460 461 // No criterion on contentLanguage has been found 462 return null; 463 } 464}