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 ViewItemContainer advancedCriteriaToCopy = searchUIModelToCopy.getAdvancedCriteria(contextualParameters); 116 if (advancedCriteriaToCopy != null) 117 { 118 View advancedCriteria = new View(); 119 List<ViewItem> advancedCriteriaViewItems = ViewHelper.copyViewItems(advancedCriteriaToCopy.getViewItems()); 120 advancedCriteria.addViewItems(advancedCriteriaViewItems); 121 setAdvancedCriteria(advancedCriteria); 122 } 123 124 setPageSize(searchUIModelToCopy.getPageSize(contextualParameters)); 125 126 setSearchUrl(searchUIModelToCopy.getSearchUrl(contextualParameters)); 127 setSearchUrlPlugin(searchUIModelToCopy.getSearchUrlPlugin(contextualParameters)); 128 129 setExportCSVUrl(searchUIModelToCopy.getExportCSVUrl(contextualParameters)); 130 setExportCSVUrlPlugin(searchUIModelToCopy.getExportCSVUrlPlugin(contextualParameters)); 131 setExportDOCUrl(searchUIModelToCopy.getExportDOCUrl(contextualParameters)); 132 setExportDOCUrlPlugin(searchUIModelToCopy.getExportDOCUrlPlugin(contextualParameters)); 133 setExportXMLUrl(searchUIModelToCopy.getExportXMLUrl(contextualParameters)); 134 setExportXMLUrlPlugin(searchUIModelToCopy.getExportXMLUrlPlugin(contextualParameters)); 135 setExportPDFUrl(searchUIModelToCopy.getExportPDFUrl(contextualParameters)); 136 setExportPDFUrlPlugin(searchUIModelToCopy.getExportPDFUrlPlugin(contextualParameters)); 137 138 setPrintUrl(searchUIModelToCopy.getPrintUrl(contextualParameters)); 139 setPrintUrlPlugin(searchUIModelToCopy.getPrintUrlPlugin(contextualParameters)); 140 } 141 142 public ViewItemContainer getAdvancedCriteria(Map<String, Object> contextualParameters) 143 { 144 return _advancedCriteria; 145 } 146 147 /** 148 * Add criteria to the advanced criteria. The created criteria reference the given paths 149 * @param criterionDefinitionHelper the criterion definition helper 150 * @param contextualParameters the contextual parameters 151 * @param references the paths to the items the criteria will reference 152 */ 153 public void addAdvancedCriteria(SearchModelCriterionDefinitionHelper criterionDefinitionHelper, Map<String, Object> contextualParameters, String... references) 154 { 155 for (String reference : references) 156 { 157 SearchModelCriterionDefinition criterion = criterionDefinitionHelper.createReferencingCriterionDefinition(this, reference, getContentTypes(contextualParameters)); 158 addAdvancedCriterion(criterion, contextualParameters); 159 } 160 } 161 162 /** 163 * Set the advanced criteria 164 * @param criteria The advanced criteria to set 165 */ 166 public void setAdvancedCriteria(ViewItemContainer criteria) 167 { 168 _advancedCriteria = criteria; 169 } 170 171 public int getPageSize(Map<String, Object> contextualParameters) 172 { 173 return _pageSize; 174 } 175 176 /** 177 * Set the page size 178 * @param pageSize The page size to set. Set to negative or 0 for unlimited or default 179 */ 180 public void setPageSize(int pageSize) 181 { 182 _pageSize = pageSize; 183 } 184 185 public String getSearchUrl(Map<String, Object> contextualParameters) 186 { 187 return _searchUrl; 188 } 189 190 /** 191 * Set the URL for search 192 * @param searchUrl The URL to set 193 */ 194 public void setSearchUrl(String searchUrl) 195 { 196 _searchUrl = searchUrl; 197 } 198 199 public String getSearchUrlPlugin(Map<String, Object> contextualParameters) 200 { 201 return _searchUrlPlugin; 202 } 203 204 /** 205 * Set the plugin name for search 206 * @param searchUrlPlugin the plugin name to set 207 */ 208 public void setSearchUrlPlugin(String searchUrlPlugin) 209 { 210 _searchUrlPlugin = searchUrlPlugin; 211 } 212 213 public String getExportCSVUrl(Map<String, Object> contextualParameters) 214 { 215 return _exportCSVUrl; 216 } 217 218 /** 219 * Set the URL for CSV export of results 220 * @param exportCSVUrl The URL to set 221 */ 222 public void setExportCSVUrl(String exportCSVUrl) 223 { 224 _exportCSVUrl = exportCSVUrl; 225 } 226 227 public String getExportCSVUrlPlugin(Map<String, Object> contextualParameters) 228 { 229 return _exportCSVUrlPlugin; 230 } 231 232 /** 233 * Set the plugin name for CSV export of results 234 * @param exportCSVUrlPlugin the plugin name to set 235 */ 236 public void setExportCSVUrlPlugin(String exportCSVUrlPlugin) 237 { 238 _exportCSVUrlPlugin = exportCSVUrlPlugin; 239 } 240 241 public String getExportDOCUrl(Map<String, Object> contextualParameters) 242 { 243 return _exportDOCUrl; 244 } 245 246 /** 247 * Set the URL for Doc export of results 248 * @param exportDOCUrl The URL to set 249 */ 250 public void setExportDOCUrl(String exportDOCUrl) 251 { 252 _exportDOCUrl = exportDOCUrl; 253 } 254 255 public String getExportDOCUrlPlugin(Map<String, Object> contextualParameters) 256 { 257 return _exportDOCUrlPlugin; 258 } 259 260 /** 261 * Set the plugin name for Doc export of results 262 * @param exportDOCUrlPlugin the plugin name to set 263 */ 264 public void setExportDOCUrlPlugin(String exportDOCUrlPlugin) 265 { 266 _exportDOCUrlPlugin = exportDOCUrlPlugin; 267 } 268 269 public String getExportXMLUrl(Map<String, Object> contextualParameters) 270 { 271 return _exportXMLUrl; 272 } 273 274 /** 275 * Set the URL for XML export of results 276 * @param exportXMLUrl The URL to set 277 */ 278 public void setExportXMLUrl(String exportXMLUrl) 279 { 280 _exportXMLUrl = exportXMLUrl; 281 } 282 283 public String getExportXMLUrlPlugin(Map<String, Object> contextualParameters) 284 { 285 return _exportXMLUrlPlugin; 286 } 287 288 /** 289 * Set the plugin name for XML export of results 290 * @param exportXMLUrlPlugin the plugin name to set 291 */ 292 public void setExportXMLUrlPlugin(String exportXMLUrlPlugin) 293 { 294 _exportXMLUrlPlugin = exportXMLUrlPlugin; 295 } 296 297 public String getExportPDFUrl(Map<String, Object> contextualParameters) 298 { 299 return _exportPDFUrl; 300 } 301 302 /** 303 * Set the URL for PDF export of results 304 * @param exportPDFUrl The URL to set 305 */ 306 public void setExportPDFUrl(String exportPDFUrl) 307 { 308 _exportPDFUrl = exportPDFUrl; 309 } 310 311 public String getExportPDFUrlPlugin(Map<String, Object> contextualParameters) 312 { 313 return _exportPDFUrlPlugin; 314 } 315 316 /** 317 * Set the plugin name for PDF export of results 318 * @param exportPDFUrlPlugin the plugin name to set 319 */ 320 public void setExportPDFUrlPlugin(String exportPDFUrlPlugin) 321 { 322 _exportPDFUrlPlugin = exportPDFUrlPlugin; 323 } 324 325 public String getPrintUrl(Map<String, Object> contextualParameters) 326 { 327 return _printUrl; 328 } 329 330 /** 331 * Set the URL for print results 332 * @param printUrl The URL to set 333 */ 334 public void setPrintUrl(String printUrl) 335 { 336 _printUrl = printUrl; 337 } 338 339 public String getPrintUrlPlugin(Map<String, Object> contextualParameters) 340 { 341 return _printUrlPlugin; 342 } 343 344 /** 345 * Set the plugin name for print results 346 * @param printUrlPlugin the plugin name to set 347 */ 348 public void setPrintUrlPlugin(String printUrlPlugin) 349 { 350 _printUrlPlugin = printUrlPlugin; 351 } 352 353 public String getSummaryView() 354 { 355 return _summaryView; 356 } 357 358 /** 359 * Set The name of the view to use for summary of the content 360 * @param summaryView the name to set 361 */ 362 public void setSummaryView(String summaryView) 363 { 364 _summaryView = summaryView; 365 } 366 367 /** 368 * 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. 369 * <br>If the final definition of the path is multiple, the column will not be sortable though. 370 * @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. 371 */ 372 protected boolean allowSortOnMultipleJoin() 373 { 374 return _sortOnMultipleJoin; 375 } 376 377 /** 378 * Set to <code>true</code> to allow sort on multiple join (default to <code>false</code>) 379 * @param sortOnMultipleJoin <code>true</code> to allow sort on multiple join, <code>false</code> otherwise 380 */ 381 public void setAllowSortOnMultipleJoin(boolean sortOnMultipleJoin) 382 { 383 _sortOnMultipleJoin = sortOnMultipleJoin; 384 } 385 386 @Override 387 public Map<String, Object> toJSON(Map<String, Object> contextualParameters) 388 { 389 Map<String, Object> jsonObject = super.toJSON(contextualParameters); 390 391 jsonObject.put("pageSize", getPageSize(contextualParameters)); 392 jsonObject.put("workspace", getWorkspace(contextualParameters)); 393 jsonObject.put("searchUrl", getSearchUrl(contextualParameters)); 394 jsonObject.put("searchUrlPlugin", getSearchUrlPlugin(contextualParameters)); 395 jsonObject.put("exportCSVUrl", getExportCSVUrl(contextualParameters)); 396 jsonObject.put("exportCSVUrlPlugin", getExportCSVUrlPlugin(contextualParameters)); 397 jsonObject.put("exportDOCUrl", getExportDOCUrl(contextualParameters)); 398 jsonObject.put("exportDOCUrlPlugin", getExportDOCUrlPlugin(contextualParameters)); 399 jsonObject.put("exportXMLUrl", getExportXMLUrl(contextualParameters)); 400 jsonObject.put("exportXMLUrlPlugin", getExportXMLUrlPlugin(contextualParameters)); 401 jsonObject.put("exportPDFUrl", getExportPDFUrl(contextualParameters)); 402 jsonObject.put("exportPDFUrlPlugin", getExportPDFUrlPlugin(contextualParameters)); 403 jsonObject.put("printUrl", getPrintUrl(contextualParameters)); 404 jsonObject.put("printUrlPlugin", getPrintUrlPlugin(contextualParameters)); 405 jsonObject.put("summaryView", getSummaryView()); 406 407 jsonObject.put("advanced-criteria", _getAdvancedCriteriaListInfo(getAdvancedCriteria(contextualParameters))); 408 409 return jsonObject; 410 } 411 412 /** 413 * Return information on a list of advanced {@link SearchModelCriterionViewItem}, serialized as a Map. 414 * @param criteria A map of advanced criteria. 415 * @return the detailed information serialized in a Map. 416 */ 417 protected Map<String, Object> _getAdvancedCriteriaListInfo(ViewItemAccessor criteria) 418 { 419 Map<String, Object> jsonObject = new LinkedHashMap<>(); 420 421 if (criteria != null) 422 { 423 // Make a copy of the criteria view 424 ViewItemAccessor criteriaCopy = new View(); 425 criteriaCopy.addViewItems(ViewHelper.copyViewItems(criteria.getViewItems())); 426 427 // Extract language criterion from the others 428 ModelViewItem languageCriterion = _getContentLanguageCriterionViewItem(criteriaCopy); 429 if (languageCriterion != null) 430 { 431 jsonObject.put("language", languageCriterion.toJSON(DefinitionContext.newInstance())); 432 433 // Remove language criterion that is already processed 434 ViewItemAccessor languageParent = languageCriterion.getParent(); 435 languageParent.removeViewItem(languageCriterion); 436 } 437 438 Map<String, Object> criteriaObject = ViewHelper.viewItemsToJSON(criteriaCopy.getViewItems(), DefinitionContext.newInstance()); 439 if (MapUtils.isNotEmpty(criteriaObject)) 440 { 441 jsonObject.put("criteria", criteriaObject); 442 } 443 } 444 445 return jsonObject; 446 } 447 448 private ModelViewItem _getContentLanguageCriterionViewItem(ViewItemAccessor criteria) 449 { 450 for (ViewItem viewItem : criteria.getViewItems()) 451 { 452 if (viewItem instanceof SearchModelCriterionViewItem criterionViewItem 453 && criterionViewItem.getDefinition() instanceof LanguageAwareCriterionDefinition) 454 { 455 return criterionViewItem; 456 } 457 else if (viewItem instanceof ViewItemContainer itemContainer) 458 { 459 ModelViewItem contentLanguageCriterion = _getContentLanguageCriterionViewItem(itemContainer); 460 if (contentLanguageCriterion != null) 461 { 462 return contentLanguageCriterion; 463 } 464 } 465 } 466 467 // No criterion on contentLanguage has been found 468 return null; 469 } 470}