001/* 002 * Copyright 2015 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.data; 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; 025import java.util.regex.Matcher; 026import java.util.regex.Pattern; 027 028import org.apache.avalon.framework.parameters.Parameters; 029import org.apache.avalon.framework.service.ServiceException; 030import org.apache.avalon.framework.service.ServiceManager; 031import org.apache.cocoon.ProcessingException; 032import org.apache.cocoon.acting.ServiceableAction; 033import org.apache.cocoon.environment.ObjectModelHelper; 034import org.apache.cocoon.environment.Redirector; 035import org.apache.cocoon.environment.Request; 036import org.apache.cocoon.environment.SourceResolver; 037 038import org.ametys.core.cocoon.JSonReader; 039import org.ametys.core.user.UserIdentity; 040import org.ametys.core.util.DateUtils; 041import org.ametys.core.util.I18nUtils; 042import org.ametys.plugins.core.user.UserHelper; 043import org.ametys.plugins.forms.Field; 044import org.ametys.plugins.forms.Field.FieldType; 045import org.ametys.plugins.forms.Form; 046import org.ametys.plugins.forms.FormsException; 047import org.ametys.plugins.forms.jcr.FormPropertiesManager; 048import org.ametys.plugins.forms.table.FormTableManager; 049import org.ametys.plugins.repository.AmetysObjectResolver; 050import org.ametys.plugins.workflow.store.JdbcWorkflowStore; 051import org.ametys.plugins.workflow.support.WorkflowProvider; 052import org.ametys.runtime.i18n.I18nizableText; 053 054import com.opensymphony.workflow.Workflow; 055import com.opensymphony.workflow.loader.StepDescriptor; 056import com.opensymphony.workflow.loader.WorkflowDescriptor; 057import com.opensymphony.workflow.spi.Step; 058 059/** 060 * Get the submitted entries of a form 061 * 062 */ 063public class GetFormEntriesAction extends ServiceableAction 064{ 065 /** Pattern for options value */ 066 protected static final Pattern __OPTION_VALUE_PATTERN = Pattern.compile("^option-([0-9]+)-value$"); 067 068 /** The internationalizable text symbolizing the absence of workflow step */ 069 protected static final I18nizableText __MESSAGE_NO_STEP = new I18nizableText("plugin.forms", "PLUGINS_FORMS_UITOOL_ENTRY_WORKFLOW_NO_WORKFLOW"); 070 071 /** The form properties manager. */ 072 protected FormPropertiesManager _formPropertiesManager; 073 074 /** The form data manager. */ 075 protected FormTableManager _formTableManager; 076 077 /** The ametys object resolver. */ 078 protected AmetysObjectResolver _resolver; 079 080 /** The workflow provider */ 081 protected WorkflowProvider _workflowProvider; 082 083 /** Utility component for internationalizable text */ 084 protected I18nUtils _i18nUtils; 085 086 /** The user helper */ 087 protected UserHelper _userHelper; 088 089 @Override 090 public void service(ServiceManager smanager) throws ServiceException 091 { 092 super.service(smanager); 093 _resolver = (AmetysObjectResolver) smanager.lookup(AmetysObjectResolver.ROLE); 094 _formPropertiesManager = (FormPropertiesManager) smanager.lookup(FormPropertiesManager.ROLE); 095 _formTableManager = (FormTableManager) smanager.lookup(FormTableManager.ROLE); 096 _workflowProvider = (WorkflowProvider) smanager.lookup(WorkflowProvider.ROLE); 097 _i18nUtils = (I18nUtils) smanager.lookup(I18nUtils.ROLE); 098 _userHelper = (UserHelper) smanager.lookup(UserHelper.ROLE); 099 } 100 101 @Override 102 public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws Exception 103 { 104 @SuppressWarnings("unchecked") 105 Map<String, Object> jsParameters = (Map<String, Object>) objectModel.get(ObjectModelHelper.PARENT_CONTEXT); 106 107 String siteName = (String) jsParameters.get("siteName"); 108 String formId = (String) jsParameters.get("id"); 109 110 int start = jsParameters.containsKey("start") ? (int) jsParameters.get("start") : 0; 111 int limit = jsParameters.containsKey("limit") ? (int) jsParameters.get("limit") : Integer.MAX_VALUE; 112 113 Form form = _formPropertiesManager.getForm(siteName, formId); 114 115 if (form == null) 116 { 117 throw new ProcessingException("The form of ID '" + formId + " can't be found in the site '" + siteName + "'."); 118 } 119 120 Workflow workflow = _workflowProvider.getExternalWorkflow(JdbcWorkflowStore.ROLE); 121 Map<String, Object> result = new HashMap<>(); 122 List<Map<String, Object>> entries2json = new ArrayList<>(); 123 try 124 { 125 Map<String, FieldValue> columns = _formTableManager.getColumns(form); 126 List<UserEntry> entries = _formTableManager.getSubmissions(form, columns, start, limit, null); 127 int totalSubmissions = _formTableManager.getTotalSubmissions(form.getId()); 128 129 result.put("id", form.getId()); 130 result.put("label", form.getLabel()); 131 result.put("total", totalSubmissions); 132 133 for (UserEntry entry : entries) 134 { 135 entries2json.add(_entry2json(entry, workflow)); 136 } 137 } 138 catch (FormsException e) 139 { 140 getLogger().error("Failed to get SQL table for form '" + form.getId() + "' for content of id.", e); 141 } 142 143 result.put("entries", entries2json); 144 145 Request request = ObjectModelHelper.getRequest(objectModel); 146 request.setAttribute(JSonReader.OBJECT_TO_READ, result); 147 return EMPTY_MAP; 148 } 149 150 private Map<String, Object> _entry2json(UserEntry entry, Workflow workflow) 151 { 152 Map<String, Object> entryAsMap = new HashMap<>(); 153 154 entryAsMap.put("id", entry.getId()); 155 entryAsMap.put("submission-date", DateUtils.dateToString(entry.getCreationDate())); 156 157 if (entry.getWorkflowId() != null) 158 { 159 entryAsMap.put("workflowStep", _workflow2json (entry, workflow)); 160 } 161 162 UserIdentity userIdentity = entry.getUserIdentity(); 163 if (userIdentity != null) 164 { 165 entryAsMap.put("user", _userHelper.user2json(userIdentity, true)); 166 } 167 168 for (FieldValue fdValue : entry.getValues()) 169 { 170 Object rawValue = fdValue.getValue(); 171 if (rawValue != null) 172 { 173 entryAsMap.put(fdValue.getColumnName() + "_raw", rawValue); 174 entryAsMap.put(fdValue.getColumnName(), _getReadableValue(fdValue.getField(), rawValue)); 175 } 176 } 177 178 return entryAsMap; 179 } 180 181 private Map<String, Object> _workflow2json (UserEntry entry, Workflow workflow) 182 { 183 Map<String, Object> workflowInfos = new LinkedHashMap<>(); 184 185 int currentStepId = 0; 186 187 long workflowId = entry.getWorkflowId(); 188 Iterator<Step> currentSteps = workflow.getCurrentSteps(workflowId).iterator(); 189 190 while (currentSteps.hasNext()) 191 { 192 Step step = currentSteps.next(); 193 currentStepId = step.getStepId(); 194 } 195 196 String workflowName = workflow.getWorkflowName(workflowId); 197 WorkflowDescriptor workflowDescriptor = workflow.getWorkflowDescriptor(workflowName); 198 StepDescriptor stepDescriptor = workflowDescriptor.getStep(currentStepId); 199 200 if (stepDescriptor != null) 201 { 202 I18nizableText workflowStepName = new I18nizableText("application", stepDescriptor.getName()); 203 204 workflowInfos.put("stepId", currentStepId); 205 workflowInfos.put("name", workflowStepName); 206 207 String[] icons = new String[] {"small", "medium", "large"}; 208 for (String icon : icons) 209 { 210 if ("application".equals(workflowStepName.getCatalogue())) 211 { 212 workflowInfos.put(icon + "Icon", "/plugins/cms/resources_workflow/" + workflowStepName.getKey() + "-" + icon + ".png"); 213 } 214 else 215 { 216 String pluginName = workflowStepName.getCatalogue().substring("plugin.".length()); 217 workflowInfos.put(icon + "Icon", "/plugins/" + pluginName + "/resources/img/workflow/" + workflowStepName.getKey() + "-" + icon + ".png"); 218 } 219 } 220 } 221 222 return workflowInfos; 223 } 224 225 /** 226 * Get label to display for field 227 * @param field The field 228 * @param value The value 229 * @return The value to display 230 */ 231 protected String _getReadableValue (Field field, Object value) 232 { 233 if (field.getType().equals(FieldType.SELECT) || field.getType().equals(FieldType.RADIO)) 234 { 235 Map<String, String> properties = field.getProperties(); 236 for (String key : properties.keySet()) 237 { 238 Matcher matcher = __OPTION_VALUE_PATTERN.matcher(key); 239 if (matcher.matches()) 240 { 241 if (((String) value).trim().equals(properties.get(key).trim())) 242 { 243 String index = matcher.group(1); 244 if (properties.containsKey("option-" + index + "-label")) 245 { 246 return properties.get("option-" + index + "-label"); 247 } 248 } 249 } 250 } 251 } 252 253 return Optional.ofNullable(value) 254 .map(Object::toString) 255 .orElse(null); 256 } 257}