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.content.consistency; 017 018import java.util.ArrayList; 019import java.util.HashMap; 020import java.util.Iterator; 021import java.util.LinkedHashMap; 022import java.util.List; 023import java.util.Map; 024import java.util.Optional; 025 026import org.apache.avalon.framework.component.Component; 027import org.apache.avalon.framework.service.ServiceException; 028import org.apache.avalon.framework.service.ServiceManager; 029import org.apache.avalon.framework.service.Serviceable; 030import org.apache.cocoon.ProcessingException; 031 032import org.ametys.cms.search.ui.model.SearchUIColumn; 033import org.ametys.cms.search.ui.model.SearchUIColumnHelper; 034import org.ametys.plugins.workflow.support.WorkflowHelper; 035import org.ametys.runtime.i18n.I18nizableText; 036import org.ametys.runtime.model.DefinitionContext; 037import org.ametys.runtime.model.ModelItem; 038 039import com.opensymphony.workflow.loader.StepDescriptor; 040 041/** 042 * Provide the search model for Content consistency search 043 */ 044public class ContentConsistencySearchModel implements Component, Serviceable 045{ 046 /** The avalon role */ 047 public static final String ROLE = ContentConsistencySearchModel.class.getName(); 048 049 private WorkflowHelper _workflowHelper; 050 private ContentConsistencyModel _contentConsistencyModel; 051 052 public void service(ServiceManager manager) throws ServiceException 053 { 054 _workflowHelper = (WorkflowHelper) manager.lookup(WorkflowHelper.ROLE); 055 _contentConsistencyModel = (ContentConsistencyModel) manager.lookup(ContentConsistencyModel.ROLE); 056 } 057 058 /** 059 * Get the model for a content consistency search 060 * @return the model 061 * @throws ProcessingException if an error occurs processing the model 062 */ 063 public Map<String, Object> getModel() throws ProcessingException 064 { 065 Map<String, Object> model = new HashMap<>(); 066 067 // Proxy configuration 068 model.put("searchMethodName", "searchResults"); 069 model.put("searchRole", "org.ametys.cms.content.consistency.ContentConsistencySearcher"); 070 071 model.put("columns", getColumns()); 072 073 model.put("criteria", getCriteria()); 074 075 model.put("facets", getFacets()); 076 077 return model; 078 } 079 080 /** 081 * Provide the list of column. 082 * Any column additional column must not be sortable as there info won't be present in the search result. 083 * @return a json description of the column 084 * @throws ProcessingException if an error occurs processing the columns 085 */ 086 protected List<Map<String, Object>> getColumns() throws ProcessingException 087 { 088 List<SearchUIColumn> columns = new ArrayList<>(); 089 090 columns.add(getSearchUIColumn(ContentConsistencyModel.TITLE, 091 new I18nizableText("plugin.cms", "PLUGINS_CMS_METADATA_TITLE_LABEL"), 092 Optional.empty(), 093 Optional.empty(), 094 false)); 095 096 columns.add(getSearchUIColumn(ContentConsistencyModel.CONTENT_TYPES, 097 new I18nizableText("plugin.cms", "UITOOL_SEARCH_CONTENT_ALL_CONTENT_TYPE"), 098 Optional.of("Ametys.plugins.cms.content.tool.GlobalContentConsistencyTool.renderContentType"), 099 Optional.empty(), 100 false)); 101 102 columns.add(getSearchUIColumn(ContentConsistencyModel.CREATOR, 103 new I18nizableText("plugin.cms", "UITOOL_SEARCH_CONTENT_CREATOR"), 104 Optional.of("Ametys.plugins.cms.search.SearchGridHelper.renderUser"), 105 Optional.empty(), 106 true)); 107 108 columns.add(getSearchUIColumn(ContentConsistencyModel.CREATION_DATE, 109 new I18nizableText("plugin.cms", "UITOOL_SEARCH_CONTENT_CREATIONDATE"), 110 Optional.empty(), 111 Optional.empty(), 112 true)); 113 114 columns.add(getSearchUIColumn(ContentConsistencyModel.LAST_CONTRIBUTOR, 115 new I18nizableText("plugin.cms", "UITOOL_SEARCH_CONTENT_AUTHOR"), 116 Optional.of("Ametys.plugins.cms.search.SearchGridHelper.renderUser"), 117 Optional.empty(), 118 false)); 119 120 columns.add(getSearchUIColumn(ContentConsistencyModel.LAST_MODIFICATION_DATE, 121 new I18nizableText("plugin.cms", "UITOOL_SEARCH_CONTENT_LASTMODIFIED"), 122 Optional.empty(), 123 Optional.empty(), 124 true)); 125 126 columns.add(getSearchUIColumn(ContentConsistencyModel.LAST_VALIDATOR, 127 new I18nizableText("plugin.cms", "UITOOL_SEARCH_CONTENT_LAST_VALIDATOR"), 128 Optional.of("Ametys.plugins.cms.search.SearchGridHelper.renderUser"), 129 Optional.empty(), 130 true)); 131 132 columns.add(getSearchUIColumn(ContentConsistencyModel.LAST_VALIDATION_DATE, 133 new I18nizableText("plugin.cms", "UITOOL_SEARCH_CONTENT_LASTVALIDATION"), 134 Optional.empty(), 135 Optional.empty(), 136 true)); 137 138 columns.add(getSearchUIColumn(ContentConsistencyModel.WORKFLOW_STEP, 139 new I18nizableText("plugin.cms", "UITOOL_SEARCH_CONTENT_WORKFLOW_STEP"), 140 Optional.of("Ametys.plugins.cms.search.SearchGridHelper.renderWorkflowStep"), 141 Optional.of("Ametys.plugins.cms.search.SearchGridHelper.convertWorkflowStep"), 142 false)); 143 144 columns.add(getSearchUIColumn(ContentConsistencyModel.DATE, 145 new I18nizableText("plugin.cms", "PLUGINS_CMS_GLOBAL_CONTENT_CONSISTENCY_CHECK_DATE"), 146 Optional.empty(), 147 Optional.empty(), 148 false)); 149 150 columns.add(getSearchUIColumn(ContentConsistencyModel.SUCCESS, 151 new I18nizableText("plugin.cms", "PLUGINS_CMS_GLOBAL_CONTENT_CONSISTENCY_SUCCESS_COUNT"), 152 Optional.empty(), 153 Optional.empty(), 154 true)); 155 156 columns.add(getSearchUIColumn(ContentConsistencyModel.UNAUTHORIZED, 157 new I18nizableText("plugin.cms", "PLUGINS_CMS_GLOBAL_CONTENT_CONSISTENCY_UNAUTHORIZED_COUNT"), 158 Optional.empty(), 159 Optional.empty(), 160 false)); 161 162 columns.add(getSearchUIColumn(ContentConsistencyModel.UNKNOWN, 163 new I18nizableText("plugin.cms", "PLUGINS_CMS_GLOBAL_CONTENT_CONSISTENCY_UNKNOWN_COUNT"), 164 Optional.empty(), 165 Optional.empty(), 166 false)); 167 168 columns.add(getSearchUIColumn(ContentConsistencyModel.NOT_FOUND, 169 new I18nizableText("plugin.cms", "PLUGINS_CMS_GLOBAL_CONTENT_CONSISTENCY_NOT_FOUND_COUNT"), 170 Optional.empty(), 171 Optional.empty(), 172 false)); 173 174 columns.add(getSearchUIColumn(ContentConsistencyModel.SERVER_ERROR, 175 new I18nizableText("plugin.cms", "PLUGINS_CMS_GLOBAL_CONTENT_CONSISTENCY_SERVER_ERROR_COUNT"), 176 Optional.empty(), 177 Optional.empty(), 178 false)); 179 180 List<Map<String, Object>> columnsInfo = new ArrayList<>(); 181 DefinitionContext definitionContext = DefinitionContext.newInstance(); 182 for (SearchUIColumn column : columns) 183 { 184 columnsInfo.add(column.toJSON(definitionContext)); 185 } 186 return columnsInfo; 187 } 188 189 /** 190 * Retrieves the column corresponding to the given item name 191 * @param name the name of the column's item 192 * @param label the column's label 193 * @param renderer the column's renderer 194 * @param converter the column's converter 195 * @param hidden <code>true</code> if the column should be hidden, <code>false</code> otherwise 196 * @return the search column's info 197 */ 198 protected SearchUIColumn getSearchUIColumn(String name, I18nizableText label, Optional<String> renderer, Optional<String> converter, boolean hidden) 199 { 200 ModelItem modelItem = _contentConsistencyModel.getModelItem(name); 201 SearchUIColumn<? extends ModelItem> column = SearchUIColumnHelper.createModelItemColumn(modelItem); 202 203 column.setLabel(label); 204 column.setRenderer(renderer); 205 column.setConverter(converter); 206 column.setHidden(hidden); 207 208 return column; 209 } 210 211 /** 212 * Get the criteria for the search 213 * @return the JSON description of the criteria 214 */ 215 protected Map<String, Object> getCriteria() 216 { 217 Map<String, Object> criteria = new LinkedHashMap<>(); // order is important here 218 criteria.put("title", Map.of( 219 "label", new I18nizableText("plugin.cms", "PLUGINS_CMS_METADATA_TITLE_LABEL"), 220 "description", new I18nizableText("plugin.cms", "PLUGINS_CMS_METADATA_TITLE_DESCRIPTION"), 221 "type", "STRING" 222 )); 223 224 List<Map<String, Object>> workflowStep = new ArrayList<>(); 225 workflowStep.add(Map.of("label", new I18nizableText("plugin.cms", "WIDGET_COMBOBOX_ALL_OPTIONS"), "value", 0)); 226 for (Iterator iterator = _workflowHelper.getWorkflowDescriptor("content").getSteps().iterator(); iterator.hasNext();) 227 { 228 StepDescriptor step = (StepDescriptor) iterator.next(); 229 workflowStep.add(Map.of("label", new I18nizableText(null, step.getName()), "value", step.getId())); 230 } 231 232 criteria.put("workflowStep", Map.of( 233 "label", new I18nizableText("plugin.cms", "UITOOL_SEARCH_CONTENT_WORKFLOW_STEP"), 234 "description", new I18nizableText("plugin.cms", "UITOOL_SEARCH_CONTENT_WORKFLOW_STEP"), 235 "type", "LONG", 236 "enumeration", workflowStep, 237 "default-value", 0 // - Tous - 238 )); 239 240 Map<String, Object> ctype = new HashMap<>(); 241 ctype.put("label", new I18nizableText("plugin.cms", "UITOOL_SEARCH_CONTENT_ALL_CONTENT_TYPE")); 242 ctype.put("description", new I18nizableText("plugin.cms", "UITOOL_SEARCH_CONTENT_ALL_CONTENT_TYPE")); 243 ctype.put("type", "STRING"); 244 ctype.put("multiple", false); 245 ctype.put("enumeration", null); 246 ctype.put("widget", "edition.select-content-types"); 247 ctype.put("widget-params", Map.of("emptyText", new I18nizableText("plugin.cms", "WIDGET_COMBOBOX_ALL_OPTIONS"))); 248 criteria.put("contentTypes", ctype); 249 250 criteria.put(ContentConsistencyModel.CREATOR, Map.of( 251 "label", new I18nizableText("plugin.cms", "UITOOL_SEARCH_CONTENT_CREATOR"), 252 "description", new I18nizableText("plugin.cms", "UITOOL_SEARCH_CONTENT_CREATOR"), 253 "type", "USER" 254 )); 255 criteria.put("contributor", Map.of( 256 "label", new I18nizableText("plugin.cms", "UITOOL_SEARCH_CONTENT_AUTHOR"), 257 "description", new I18nizableText("plugin.cms", "UITOOL_SEARCH_CONTENT_AUTHOR"), 258 "type", "USER" 259 )); 260 criteria.put(ContentConsistencyModel.LAST_VALIDATOR, Map.of( 261 "label", new I18nizableText("plugin.cms", "UITOOL_SEARCH_CONTENT_LAST_VALIDATOR"), 262 "description", new I18nizableText("plugin.cms", "UITOOL_SEARCH_CONTENT_LAST_VALIDATOR"), 263 "type", "USER" 264 )); 265 return criteria; 266 } 267 268 /** 269 * Get the facets for the search 270 * @return the JSON description of the facets 271 */ 272 protected List<Map<String, Object>> getFacets() 273 { 274 List<Map<String, Object>> facets = new ArrayList<>(); 275 facets.add(Map.of( 276 "name", ContentConsistencyModel.CREATOR, 277 "label", new I18nizableText("plugin.cms", "UITOOL_SEARCH_CONTENT_CREATOR"), 278 "type", "criterion", 279 "children", new ArrayList())); 280 facets.add(Map.of( 281 "name", ContentConsistencyModel.LAST_CONTRIBUTOR, 282 "label", new I18nizableText("plugin.cms", "UITOOL_SEARCH_CONTENT_AUTHOR"), 283 "type", "criterion", 284 "children", new ArrayList())); // needs to be mutable to add the value later 285 facets.add(Map.of( 286 "name", ContentConsistencyModel.LAST_VALIDATOR, 287 "label", new I18nizableText("plugin.cms", "UITOOL_SEARCH_CONTENT_LAST_VALIDATOR"), 288 "type", "criterion", 289 "children", new ArrayList())); // needs to be mutable to add the value later 290 facets.add(Map.of( 291 "name", ContentConsistencyModel.WORKFLOW_STEP, 292 "label", new I18nizableText("plugin.cms", "UITOOL_SEARCH_CONTENT_WORKFLOW_STEP"), 293 "type", "criterion", 294 "children", new ArrayList())); // needs to be mutable to add the value later 295 facets.add(Map.of( 296 "name", ContentConsistencyModel.CONTENT_TYPES, 297 "label", new I18nizableText("plugin.cms", "UITOOL_SEARCH_CONTENT_ALL_CONTENT_TYPE"), 298 "type", "criterion", 299 "children", new ArrayList())); // needs to be mutable to add the value later 300 return facets; 301 } 302}