001/* 002 * Copyright 2019 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.tree; 017 018import java.util.HashMap; 019import java.util.List; 020import java.util.Map; 021 022import org.apache.avalon.framework.service.ServiceException; 023import org.apache.avalon.framework.service.ServiceManager; 024import org.apache.commons.lang3.StringUtils; 025 026import org.ametys.cms.repository.Content; 027import org.ametys.cms.repository.WorkflowAwareContent; 028import org.ametys.core.ui.Callable; 029import org.ametys.odf.ODFHelper; 030import org.ametys.odf.ProgramItem; 031import org.ametys.odf.course.Course; 032import org.ametys.odf.course.ShareableCourseHelper; 033import org.ametys.odf.course.ShareableCourseStatusHelper; 034import org.ametys.odf.course.ShareableCourseStatusHelper.ShareableStatus; 035import org.ametys.odf.courselist.CourseList; 036import org.ametys.odf.orgunit.OrgUnit; 037import org.ametys.plugins.contentstree.ContentsTreeHelper; 038import org.ametys.plugins.workflow.repository.WorkflowAwareAmetysObject; 039import org.ametys.plugins.workflow.support.WorkflowProvider; 040import org.ametys.plugins.workflow.support.WorkflowProvider.AmetysObjectWorkflow; 041import org.ametys.runtime.i18n.I18nizableText; 042 043import com.opensymphony.workflow.loader.StepDescriptor; 044import com.opensymphony.workflow.loader.WorkflowDescriptor; 045 046/** 047 * Helper ODF contents tree 048 * 049 */ 050public class ODFContentsTreeHelper extends ContentsTreeHelper 051{ 052 /** The Avalon role */ 053 @SuppressWarnings("hiding") 054 public static final String ROLE = ODFContentsTreeHelper.class.getName(); 055 056 /** The ODF helper */ 057 protected ODFHelper _odfHelper; 058 /** The workflow provider */ 059 protected WorkflowProvider _workflowProvider; 060 /** The shareable course status helper */ 061 protected ShareableCourseStatusHelper _shareableStatusHelper; 062 /** The shareable course helper */ 063 protected ShareableCourseHelper _shareableCourseHelper; 064 065 @Override 066 public void service(ServiceManager smanager) throws ServiceException 067 { 068 super.service(smanager); 069 070 _workflowProvider = (WorkflowProvider) smanager.lookup(WorkflowProvider.ROLE); 071 _odfHelper = (ODFHelper) smanager.lookup(ODFHelper.ROLE); 072 _shareableCourseHelper = (ShareableCourseHelper) smanager.lookup(ShareableCourseHelper.ROLE); 073 _shareableStatusHelper = (ShareableCourseStatusHelper) smanager.lookup(ShareableCourseStatusHelper.ROLE); 074 } 075 076 @Override 077 @Callable 078 public Map<String, Object> getRootNodeInformations(String contentId) 079 { 080 Map<String, Object> infos = super.getRootNodeInformations(contentId); 081 infos.put("handleShareableCourse", _shareableCourseHelper.handleShareableCourse()); 082 return infos; 083 } 084 085 @Override 086 protected Map<String, Object> content2Json(Content content) 087 { 088 Map<String, Object> infos = super.content2Json(content); 089 if (content instanceof ProgramItem programItem) 090 { 091 boolean isShared = isShared(programItem); 092 boolean isSharedByParents = !isShared ? isSharedByParents(programItem) : false; 093 infos.put("code", getProgramItemDisplayCode((Content & ProgramItem) content)); 094 infos.put("workflowStep", getWorkflowStep(content)); 095 infos.put("isShared", isShared); 096 infos.put("isParentShared", isSharedByParents); 097 infos.put("isPublishable", programItem.isPublishable()); 098 infos.put("isParentPublishable", _isParentPublishable(programItem)); 099 100 if (content instanceof Course) 101 { 102 infos.put("shareableStatus", getShareableStatus((Course) content)); 103 } 104 else if (content instanceof CourseList) 105 { 106 CourseList courseList = (CourseList) content; 107 infos.put("courseList-type", courseList.getType()); 108 } 109 } 110 else if (content instanceof OrgUnit) 111 { 112 infos.put("code", ((OrgUnit) content).getUAICode()); 113 } 114 115 return infos; 116 } 117 118 private boolean _isParentPublishable(ProgramItem content) 119 { 120 List<ProgramItem> parents = _odfHelper.getParentProgramItems(content); 121 if (parents.isEmpty()) 122 { 123 return true; 124 } 125 126 return parents.stream() 127 .filter(ProgramItem::isPublishable) 128 .filter(this::_isParentPublishable) 129 .findAny() 130 .isPresent(); 131 } 132 133 /** 134 * Get the ProgramItem code we want to display. 135 * @param <T> The type of the program element, should be a subclasse of {@link ProgramItem} and {@link Content} 136 * @param programItem The program item 137 * @return The code to display 138 */ 139 protected <T extends ProgramItem & Content> Object getProgramItemDisplayCode(T programItem) 140 { 141 return programItem.getCode(); 142 } 143 144 @Override 145 protected boolean isContentMatching(Content content, String value) 146 { 147 boolean matchTitle = super.isContentMatching(content, value); 148 if (!matchTitle) 149 { 150 if (content instanceof ProgramItem) 151 { 152 // Try with code 153 String code = StringUtils.stripAccents(((ProgramItem) content).getCode().toLowerCase()); 154 return code.contains(value); 155 } 156 else if (content instanceof OrgUnit) 157 { 158 // Try with code 159 String code = StringUtils.stripAccents(((OrgUnit) content).getUAICode().toLowerCase()); 160 return code.contains(value); 161 } 162 } 163 164 return matchTitle; 165 } 166 167 /** 168 * Get workflow step information 169 * @param content the content the content 170 * @return the workflow step information 171 */ 172 protected Map<String, Object> getWorkflowStep(Content content) 173 { 174 Map<String, Object> workflowInfos = new HashMap<>(); 175 176 if (content instanceof WorkflowAwareAmetysObject) 177 { 178 WorkflowAwareContent waContent = (WorkflowAwareContent) content; 179 180 long workflowId = waContent.getWorkflowId(); 181 int currentStepId = Math.toIntExact(waContent.getCurrentStepId()); 182 183 AmetysObjectWorkflow workflow = _workflowProvider.getAmetysObjectWorkflow(waContent); 184 185 String workflowName = workflow.getWorkflowName(workflowId); 186 WorkflowDescriptor workflowDescriptor = workflow.getWorkflowDescriptor(workflowName); 187 188 if (workflowDescriptor != null) 189 { 190 StepDescriptor stepDescriptor = workflowDescriptor.getStep(currentStepId); 191 if (stepDescriptor != null) 192 { 193 I18nizableText workflowStepName = new I18nizableText("application", stepDescriptor.getName()); 194 195 workflowInfos.put("stepId", currentStepId); 196 workflowInfos.put("name", workflowStepName); 197 198 String[] icons = new String[] {"small", "medium", "large"}; 199 for (String icon : icons) 200 { 201 if ("application".equals(workflowStepName.getCatalogue())) 202 { 203 workflowInfos.put(icon + "Icon", "/plugins/cms/resources_workflow/" + workflowStepName.getKey() + "-" + icon + ".png"); 204 } 205 else 206 { 207 String pluginName = workflowStepName.getCatalogue().substring("plugin.".length()); 208 workflowInfos.put(icon + "Icon", "/plugins/" + pluginName + "/resources/img/workflow/" + workflowStepName.getKey() + "-" + icon + ".png"); 209 } 210 } 211 } 212 } 213 } 214 215 return workflowInfos; 216 } 217 218 /** 219 * Get the shared status of this program item 220 * @param programItem the program item 221 * @return true if the program item belongs to more than one program item 222 */ 223 protected boolean isShared(ProgramItem programItem) 224 { 225 return _odfHelper.getParentProgramItems(programItem).size() > 1; 226 } 227 228 /** 229 * Check if the parent of a program item is shared 230 * @param programItem the program item 231 * @return true if the parent of the program item is shared 232 */ 233 protected boolean isSharedByParents(ProgramItem programItem) 234 { 235 for (ProgramItem parent : _odfHelper.getParentProgramItems(programItem)) 236 { 237 return _odfHelper.getParentProgramItems(parent).size() > 1 ? true : isSharedByParents(parent); 238 } 239 return false; 240 } 241 242 /** 243 * Get the shareable course status as String 244 * @param course the course 245 * @return the shareable status 246 */ 247 protected String getShareableStatus(Course course) 248 { 249 if (_shareableCourseHelper.handleShareableCourse()) 250 { 251 ShareableStatus shareableStatus = _shareableStatusHelper.getShareableStatus(course); 252 return shareableStatus.name().toLowerCase(); 253 } 254 255 return null; 256 } 257}