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.cart.actions; 017 018import java.util.ArrayList; 019import java.util.Collections; 020import java.util.Comparator; 021import java.util.Date; 022import java.util.HashMap; 023import java.util.List; 024import java.util.Map; 025 026import org.apache.avalon.framework.parameters.Parameters; 027import org.apache.avalon.framework.service.ServiceException; 028import org.apache.avalon.framework.service.ServiceManager; 029import org.apache.cocoon.acting.ServiceableAction; 030import org.apache.cocoon.environment.ObjectModelHelper; 031import org.apache.cocoon.environment.Redirector; 032import org.apache.cocoon.environment.Request; 033import org.apache.cocoon.environment.SourceResolver; 034import org.apache.commons.lang.ArrayUtils; 035 036import org.ametys.cms.repository.Content; 037import org.ametys.cms.repository.WorkflowAwareContent; 038import org.ametys.core.cocoon.JSonReader; 039import org.ametys.core.user.CurrentUserProvider; 040import org.ametys.core.user.UserIdentity; 041import org.ametys.core.user.UserManager; 042import org.ametys.plugins.cart.Cart; 043import org.ametys.plugins.cart.CartElement; 044import org.ametys.plugins.cart.ContentElement; 045import org.ametys.plugins.core.user.UserHelper; 046import org.ametys.plugins.repository.AmetysObjectResolver; 047import org.ametys.plugins.repository.AmetysRepositoryException; 048import org.ametys.plugins.repository.UnknownAmetysObjectException; 049import org.ametys.plugins.repository.version.VersionAwareAmetysObject; 050import org.ametys.plugins.workflow.store.AmetysStep; 051import org.ametys.plugins.workflow.support.WorkflowHelper; 052import org.ametys.plugins.workflow.support.WorkflowProvider; 053import org.ametys.plugins.workflow.support.WorkflowProvider.AmetysObjectWorkflow; 054import org.ametys.runtime.i18n.I18nizableText; 055import org.ametys.runtime.parameter.ParameterHelper; 056 057import com.opensymphony.workflow.WorkflowException; 058import com.opensymphony.workflow.spi.Step; 059 060/** 061 * SAX a {@link Cart} 062 * 063 */ 064public class GetCartElementsAction extends ServiceableAction 065{ 066 /** The Ametys object resolver */ 067 protected AmetysObjectResolver _resolver; 068 /** The workflow */ 069 protected WorkflowProvider _workflowProvider; 070 /** The workflow helper */ 071 protected WorkflowHelper _workflowHelper; 072 /** The current user provider */ 073 protected CurrentUserProvider _userProvider; 074 /** The user manager */ 075 protected UserManager _userManager; 076 /** The user helper */ 077 protected UserHelper _userHelper; 078 079 @Override 080 public void service(ServiceManager serviceManager) throws ServiceException 081 { 082 super.service(serviceManager); 083 _resolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE); 084 _workflowProvider = (WorkflowProvider) serviceManager.lookup(WorkflowProvider.ROLE); 085 _workflowHelper = (WorkflowHelper) serviceManager.lookup(WorkflowHelper.ROLE); 086 _userManager = (UserManager) serviceManager.lookup(UserManager.ROLE); 087 _userProvider = (CurrentUserProvider) serviceManager.lookup(CurrentUserProvider.ROLE); 088 _userHelper = (UserHelper) serviceManager.lookup(UserHelper.ROLE); 089 } 090 091 @Override 092 public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws Exception 093 { 094 @SuppressWarnings("unchecked") 095 Map jsParameters = (Map<String, Object>) objectModel.get(ObjectModelHelper.PARENT_CONTEXT); 096 097 String id = (String) jsParameters.get("cartId"); 098 099 Map<String, Object> result = new HashMap<>(); 100 List<Map<String, Object>> nodes = new ArrayList<>(); 101 int total = 0; 102 103 try 104 { 105 Cart cart = _resolver.resolveById(id); 106 107 UserIdentity user = _userProvider.getUser(); 108 if (cart.canRead(user)) 109 { 110 result.put("label", cart.getTitle()); 111 result.put("description", cart.getDescription()); 112 result.put("visibility", cart.getVisibility().toString()); 113 114 List<CartElement> elements = cart.getElements(); 115 for (CartElement elmt : elements) 116 { 117 nodes.addAll(elementToJSON(elmt)); 118 } 119 total = elements.size(); 120 } 121 122 result.put("cartElements", nodes); 123 result.put("total", total); 124 } 125 catch (UnknownAmetysObjectException e) 126 { 127 result.put("unknown-cart", true); 128 } 129 130 Request request = ObjectModelHelper.getRequest(objectModel); 131 request.setAttribute(JSonReader.OBJECT_TO_READ, result); 132 133 return EMPTY_MAP; 134 } 135 136 /** 137 * Gets a cart element to JSON format 138 * @param elmt The elemetnt 139 * @return The element's properties 140 */ 141 protected List<Map<String, Object>> elementToJSON (CartElement elmt) 142 { 143 List<Map<String, Object>> elmts = new ArrayList<>(); 144 145 HashMap<String, Object> infos = new HashMap<>(); 146 147 infos.put("elmtId", elmt.getId()); 148 infos.put("title", elmt.getTitle()); 149 infos.put("description", elmt.getDescription()); 150 151 infos.put("lastModification", ParameterHelper.valueToString(elmt.getLastModified())); 152 infos.put("lastContributor", _userHelper.user2json(elmt.getLastContributor())); 153 154 infos.put("glyphIcon", elmt.getGlyphIcon()); 155 infos.put("smallIcon", elmt.getSmallIcon()); 156 infos.put("mediumIcon", elmt.getMediumIcon()); 157 158 infos.put("type", elmt.getType()); 159 160 if (elmt instanceof ContentElement) 161 { 162 Content content = _resolver.resolveById(elmt.getId()); 163 infos.put("workflow-step", workflowStepToJSON(content)); 164 } 165 166 List<I18nizableText> groups = elmt.getGroups(); 167 for (I18nizableText group : groups) 168 { 169 @SuppressWarnings("unchecked") 170 HashMap<String, Object> clonedInfos = (HashMap<String, Object>) infos.clone(); 171 clonedInfos.put("group", group); 172 elmts.add(clonedInfos); 173 } 174 175 return elmts; 176 } 177 178 /** 179 * Gets the workflow step if the content is a <code>WorkflowAwareContent</code> 180 * @param content The content 181 * @return The workflow step's properties 182 */ 183 protected Map<String, Object> workflowStepToJSON (Content content) 184 { 185 Map<String, Object> infos = new HashMap<>(); 186 187 if (content instanceof WorkflowAwareContent) 188 { 189 WorkflowAwareContent waContent = (WorkflowAwareContent) content; 190 191 try 192 { 193 AmetysObjectWorkflow workflow = _workflowProvider.getAmetysObjectWorkflow(waContent); 194 long workflowId = waContent.getWorkflowId(); 195 String workflowName = workflow.getWorkflowName(workflowId); 196 197 Step currentStep = _getCurrentStep(waContent, workflow); 198 199 int currentStepId = currentStep.getStepId(); 200 201 I18nizableText workflowStepName = new I18nizableText("application", _workflowHelper.getStepName(workflowName, currentStepId)); 202 203 infos.put("id", String.valueOf(currentStepId)); 204 infos.put("name", workflowStepName); 205 if ("application".equals(workflowStepName.getCatalogue())) 206 { 207 infos.put("icon-small", "/plugins/cms/resources_workflow/" + workflowStepName.getKey() + "-small.png"); 208 infos.put("icon-medium", "/plugins/cms/resources_workflow/" + workflowStepName.getKey() + "-medium.png"); 209 infos.put("icon-large", "/plugins/cms/resources_workflow/" + workflowStepName.getKey() + "-large.png"); 210 } 211 else 212 { 213 String pluginName = workflowStepName.getCatalogue().substring("plugin.".length()); 214 infos.put("icon-small", "/plugins/" + pluginName + "/resources/img/workflow/" + workflowStepName.getKey() + "-small.png"); 215 infos.put("icon-medium", "/plugins/" + pluginName + "/resources/img/workflow/" + workflowStepName.getKey() + "-medium.png"); 216 infos.put("icon-large", "/plugins/" + pluginName + "/resources/img/workflow/" + workflowStepName.getKey() + "-large.png"); 217 } 218 } 219 catch (AmetysRepositoryException e) 220 { 221 // Current step id was not positioned 222 } 223 catch (WorkflowException e) 224 { 225 // Ignore, just don't SAX the workflow step. 226 } 227 } 228 229 return infos; 230 } 231 232 /** 233 * Get a content's step, wherever it works on the base version or not. 234 * @param content the content. 235 * @param workflow the workflow instance bound to this content 236 * @return the content's workflow step. 237 * @throws WorkflowException if an error occurs. 238 */ 239 protected Step _getCurrentStep(WorkflowAwareContent content, AmetysObjectWorkflow workflow) throws WorkflowException 240 { 241 long workflowId = content.getWorkflowId(); 242 Step currentStep = (Step) workflow.getCurrentSteps(workflowId).get(0); 243 244 if (content instanceof VersionAwareAmetysObject) 245 { 246 VersionAwareAmetysObject vaContent = (VersionAwareAmetysObject) content; 247 String currentRevision = vaContent.getRevision(); 248 249 if (currentRevision != null) 250 { 251 252 String[] allRevisions = vaContent.getAllRevisions(); 253 int currentRevIndex = ArrayUtils.indexOf(allRevisions, currentRevision); 254 255 if (currentRevIndex > -1 && currentRevIndex < (allRevisions.length - 1)) 256 { 257 String nextRevision = allRevisions[currentRevIndex + 1]; 258 259 Date currentRevTimestamp = vaContent.getRevisionTimestamp(); 260 Date nextRevTimestamp = vaContent.getRevisionTimestamp(nextRevision); 261 262 // Get all steps between the two revisions. 263 List<Step> steps = _workflowHelper.getStepsBetween(workflow, workflowId, currentRevTimestamp, nextRevTimestamp); 264 265 // In the old workflow structure 266 // We take the second, which is current revision's last step. 267 if (steps.size() > 0 && steps.get(0) instanceof AmetysStep) 268 { 269 AmetysStep amStep = (AmetysStep) steps.get(0); 270 if (amStep.getProperty("actionFinishDate") != null) 271 { 272 // New workflow structure detected: cut the first workflow step 273 // in the list, as it belongs to the next version. 274 steps = steps.subList(1, steps.size()); 275 } 276 } 277 278 // Order by step descendant. 279 Collections.sort(steps, new Comparator<Step>() 280 { 281 public int compare(Step step1, Step step2) 282 { 283 return -new Long(step1.getId()).compareTo(step2.getId()); 284 } 285 }); 286 287 // The first step in the list is the current version's last workflow step. 288 if (steps.size() > 0) 289 { 290 currentStep = steps.get(0); 291 } 292 } 293 } 294 } 295 return currentStep; 296 } 297 298}