001/* 002 * Copyright 2017 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.odf.workflow; 017 018import java.util.Collection; 019import java.util.HashMap; 020import java.util.HashSet; 021import java.util.List; 022import java.util.Map; 023import java.util.Set; 024 025import org.apache.avalon.framework.component.Component; 026import org.apache.avalon.framework.service.ServiceException; 027import org.apache.avalon.framework.service.ServiceManager; 028import org.apache.avalon.framework.service.Serviceable; 029import org.apache.commons.lang3.StringUtils; 030 031import org.ametys.cms.repository.Content; 032import org.ametys.cms.repository.WorkflowAwareContent; 033import org.ametys.core.ui.Callable; 034import org.ametys.odf.ODFHelper; 035import org.ametys.odf.ProgramItem; 036import org.ametys.odf.course.Course; 037import org.ametys.odf.orgunit.OrgUnit; 038import org.ametys.odf.program.AbstractProgram; 039import org.ametys.plugins.repository.AmetysObjectResolver; 040import org.ametys.plugins.repository.UnknownAmetysObjectException; 041import org.ametys.plugins.workflow.support.WorkflowProvider; 042import org.ametys.plugins.workflow.support.WorkflowProvider.AmetysObjectWorkflow; 043import org.ametys.runtime.plugin.component.AbstractLogEnabled; 044 045import com.opensymphony.workflow.spi.Step; 046 047/** 048 * Helper for ODF contents on their workflow 049 * 050 */ 051public class ODFWorkflowHelper extends AbstractLogEnabled implements Component, Serviceable 052{ 053 /** The component role. */ 054 public static final String ROLE = ODFWorkflowHelper.class.getName(); 055 056 /** The validate step id */ 057 public static final int VALIDATED_STEP_ID = 3; 058 059 /** The Ametys object resolver */ 060 protected AmetysObjectResolver _resolver; 061 /** The workflow provider */ 062 protected WorkflowProvider _workflowProvider; 063 /** The ODF helper */ 064 protected ODFHelper _odfHelper; 065 066 @Override 067 public void service(ServiceManager manager) throws ServiceException 068 { 069 _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE); 070 _workflowProvider = (WorkflowProvider) manager.lookup(WorkflowProvider.ROLE); 071 _odfHelper = (ODFHelper) manager.lookup(ODFHelper.ROLE); 072 } 073 074 /** 075 * Check if the contents can be validated. A content can be validated only if all its referenced contents are already validated. 076 * @param contentIds The id of contents to check 077 * @return A map with success key to true if the content can be validated. A map with the invalidated contents otherwise. 078 */ 079 @Callable 080 public Map<String, Object> canValidContent(List<String> contentIds) 081 { 082 Map<String, Object> result = new HashMap<>(); 083 084 Map<String, Object> contentsInError = new HashMap<>(); 085 086 for (String contentId : contentIds) 087 { 088 WorkflowAwareContent content = _resolver.resolveById(contentId); 089 090 Map<String, String> invalidatedContents = new HashMap<>(); 091 _checkValidateStep(content, invalidatedContents); 092 093 if (!invalidatedContents.isEmpty()) 094 { 095 contentsInError.put(content.getTitle(), invalidatedContents); 096 } 097 } 098 result.put("contentsInError", contentsInError); 099 result.put("success", contentsInError.isEmpty()); 100 return result; 101 } 102 103 /** 104 * Determines if a content is already in validated step 105 * @param content The content to test 106 * @return true if the content is already validated 107 */ 108 public boolean isInValidatedStep (WorkflowAwareContent content) 109 { 110 AmetysObjectWorkflow workflow = _workflowProvider.getAmetysObjectWorkflow(content); 111 long workflowId = content.getWorkflowId(); 112 113 List<Step> steps = workflow.getCurrentSteps(workflowId); 114 for (Step step : steps) 115 { 116 if (step.getStepId() == VALIDATED_STEP_ID) 117 { 118 return true; 119 } 120 } 121 122 return false; 123 } 124 125 private void _checkValidateStep (WorkflowAwareContent content, Map<String, String> invalidatedContent) 126 { 127 if (content instanceof ProgramItem) 128 { 129 // Check the structure recursively 130 List<ProgramItem> children = _odfHelper.getChildProgramItems((ProgramItem) content); 131 for (ProgramItem child : children) 132 { 133 WorkflowAwareContent waChild = (WorkflowAwareContent) child; 134 if (!isInValidatedStep(waChild)) 135 { 136 if (!invalidatedContent.containsKey(waChild.getId())) 137 { 138 invalidatedContent.put(waChild.getId(), _getTitle(waChild)); 139 } 140 } 141 else 142 { 143 // The item is already validated. Continue to its own children. 144 _checkValidateStep(waChild, invalidatedContent); 145 } 146 } 147 } 148 149 // Validate others referenced contents 150 if (content instanceof AbstractProgram) 151 { 152 _checkReferencedContents(((AbstractProgram) content).getOrgUnits(), invalidatedContent); 153 _checkReferencedContents(((AbstractProgram) content).getContacts(), invalidatedContent); 154 155 Set<String> persons = new HashSet<>(); 156 Map<String, String[]> personsInChargeByRole = ((AbstractProgram) content).getPersonsInCharge(); 157 for (String role : personsInChargeByRole.keySet()) 158 { 159 for (String person : personsInChargeByRole.get(role)) 160 { 161 persons.add(person); 162 } 163 } 164 _checkReferencedContents(persons, invalidatedContent); 165 } 166 else if (content instanceof Course) 167 { 168 _checkReferencedContents(((Course) content).getOrgUnits(), invalidatedContent); 169 _checkReferencedContents(((Course) content).getContacts(), invalidatedContent); 170 _checkReferencedContents(((Course) content).getPersonsInCharge(), invalidatedContent); 171 } 172 else if (content instanceof OrgUnit) 173 { 174 _checkReferencedContents(((OrgUnit) content).getContacts(), invalidatedContent); 175 } 176 } 177 178 private String _getTitle(Content content) 179 { 180 String title = content.getTitle(); 181 if (content instanceof ProgramItem) 182 { 183 title += " (" + ((ProgramItem) content).getCode() + ")"; 184 } 185 return title; 186 } 187 188 private void _checkReferencedContents (Collection<String> refContentIds, Map<String, String> invalidatedContent) 189 { 190 for (String id : refContentIds) 191 { 192 try 193 { 194 if (StringUtils.isNotEmpty(id)) 195 { 196 WorkflowAwareContent refContent = _resolver.resolveById(id); 197 _checkValidateStep(refContent, invalidatedContent); 198 } 199 } 200 catch (UnknownAmetysObjectException e) 201 { 202 // Nothing 203 } 204 } 205 } 206}