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