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.cms.content.referencetable; 017 018import java.util.HashMap; 019import java.util.List; 020import java.util.Map; 021import java.util.stream.Collectors; 022 023import org.apache.avalon.framework.service.ServiceException; 024import org.apache.avalon.framework.service.ServiceManager; 025 026import org.ametys.cms.content.ContentHelper; 027import org.ametys.cms.contenttype.ContentType; 028import org.ametys.cms.contenttype.ContentTypeExtensionPoint; 029import org.ametys.cms.contenttype.ContentTypesHelper; 030import org.ametys.cms.contenttype.MetadataDefinition; 031import org.ametys.cms.contenttype.MetadataType; 032import org.ametys.cms.repository.Content; 033import org.ametys.cms.repository.DefaultContent; 034import org.ametys.core.ui.Callable; 035import org.ametys.core.ui.StaticClientSideElement; 036import org.ametys.plugins.repository.AmetysObjectIterable; 037import org.ametys.plugins.repository.AmetysObjectResolver; 038import org.ametys.plugins.repository.AmetysRepositoryException; 039 040import com.opensymphony.workflow.WorkflowException; 041 042/** 043 * This element creates a button enabling to do operation on reference table contents which can have a child. 044 */ 045public class HierarchicalReferenceTableClientSideElement extends StaticClientSideElement 046{ 047 /** The extension point for content types */ 048 protected ContentTypeExtensionPoint _contentTypeEP; 049 /** The helper component for hierarchical reference tables */ 050 protected HierarchicalReferenceTablesHelper _hierarchicalReferenceTableContentsHelper; 051 /** The Ametys Object resolver */ 052 protected AmetysObjectResolver _resolver; 053 /** The content types helper */ 054 protected ContentTypesHelper _cTypeHelper; 055 /** The content helper */ 056 protected ContentHelper _contentHelper; 057 058 @Override 059 public void service(ServiceManager smanager) throws ServiceException 060 { 061 super.service(smanager); 062 _contentTypeEP = (ContentTypeExtensionPoint) smanager.lookup(ContentTypeExtensionPoint.ROLE); 063 _hierarchicalReferenceTableContentsHelper = (HierarchicalReferenceTablesHelper) smanager.lookup(HierarchicalReferenceTablesHelper.ROLE); 064 _resolver = (AmetysObjectResolver) smanager.lookup(AmetysObjectResolver.ROLE); 065 _cTypeHelper = (ContentTypesHelper) smanager.lookup(ContentTypesHelper.ROLE); 066 _contentHelper = (ContentHelper) smanager.lookup(ContentHelper.ROLE); 067 } 068 069 /** 070 * Returns true if the given content can have a child, according to its hierarchy. See {@link ContentType#getParentMetadata()} 071 * @param contentId The id of the content 072 * @return true if the given content can have a child, according to its hierarchy 073 */ 074 @Callable 075 public boolean canHaveChild(String contentId) 076 { 077 try 078 { 079 Content content = _resolver.resolveById(contentId); 080 for (String cTypeId : content.getTypes()) 081 { 082 ContentType cType = _contentTypeEP.getExtension(cTypeId); 083 if (cType != null && _hierarchicalReferenceTableContentsHelper.hasChildContentType(cType)) 084 { 085 return true; 086 } 087 } 088 } 089 catch (AmetysRepositoryException e) 090 { 091 // Ignore 092 } 093 094 return false; 095 } 096 097 /** 098 * Get the hierarchy properties of the content types tree 099 * @param leafContentTypeId The id of the leaf content type, which defines the hierarchy. 100 * @return the hierarchy properties 101 */ 102 @Callable 103 public Map<String, Object> getReferenceTableProperties(String leafContentTypeId) 104 { 105 Map<String, Object> result = new HashMap<>(); 106 107 result.put("rootContentType", getContentTypeForRoot(leafContentTypeId)); 108 result.put("supportedContentTypes", _hierarchicalReferenceTableContentsHelper.getHierarchicalContentTypes(leafContentTypeId)); 109 ContentType leafContentType = _contentTypeEP.getExtension(leafContentTypeId); 110 result.put("allowCandidates", _hierarchicalReferenceTableContentsHelper.supportCandidates(leafContentType)); 111 return result; 112 } 113 114 /** 115 * Gets the content types ids for a child of the given content (must be non-leaf in a hierarchy of reference tables contents) 116 * @param parentContentId The id of the parent content 117 * @return the content types ids 118 */ 119 @Callable 120 public List<String> getContentTypesForChild(String parentContentId) 121 { 122 Content parentContent = _resolver.resolveById(parentContentId); 123 List<ContentType> childContentTypes = _hierarchicalReferenceTableContentsHelper.getChildContentTypes(parentContent); 124 125 return childContentTypes.stream().map(ContentType::getId).collect(Collectors.toList()); 126 } 127 128 /** 129 * Gets the content type id and the default title for a child of the root node of the hierarchy of reference table contents, defined by the given leaf content type 130 * @param leafContentTypeId The id of the leaf content type, which defines the hierarchy. 131 * @return the content type id for the root node of the hierarchy of reference table contents 132 */ 133 @Callable 134 public String getContentTypeForRoot(String leafContentTypeId) 135 { 136 ContentType leafContentType = _contentTypeEP.getExtension(leafContentTypeId); 137 ContentType rootContentType = _hierarchicalReferenceTableContentsHelper.getTopLevelType(leafContentType); 138 139 if (rootContentType != null) 140 { 141 return rootContentType.getId(); 142 } 143 144 return null; 145 } 146 147 /** 148 * Return the leafContentType 149 * @param contentTypeId the content type id 150 * @param contentId the content id to get the leaf content type from 151 * @return the map containing the properties of the leaf content type 152 */ 153 @Callable 154 public Map<String, Object> getLeafContentType(String contentTypeId, String contentId) 155 { 156 ContentType cType = _contentTypeEP.getExtension(contentTypeId); 157 if (_hierarchicalReferenceTableContentsHelper.isLeaf(cType)) 158 { 159 return _cTypeHelper.getContentTypeProperties(cType); 160 } 161 else 162 { 163 AmetysObjectIterable<Content> contents = _hierarchicalReferenceTableContentsHelper.getDirectChildren(_resolver.resolveById(contentId)); 164 for (Content content: contents) 165 { 166 return getLeafContentType(contentTypeId, content.getId()); 167 } 168 } 169 return null; 170 } 171 172 /** 173 * Get the path of metadata holding the parent 174 * @param contentId The id of content 175 * @return the path of parent metadata or null if not found 176 */ 177 @Callable 178 public String getParentMetadataPath(String contentId) 179 { 180 Content content = _resolver.resolveById(contentId); 181 List<ContentType> childrenContentTypes = _hierarchicalReferenceTableContentsHelper.getChildContentTypes(content); 182 for (ContentType contentType : childrenContentTypes) 183 { 184 MetadataDefinition parentMetadata = contentType.getParentMetadata(); 185 if (parentMetadata != null) 186 { 187 return parentMetadata.getId(); 188 } 189 } 190 return null; 191 } 192 193 /** 194 * Get the path of metadata when root is selected 195 * @param leafContentTypeId The id of content 196 * @return the path of parent metadata or null if not found 197 */ 198 @Callable 199 public String getParentMetadataPathForRoot(String leafContentTypeId) 200 { 201 ContentType leafContentType = _contentTypeEP.getExtension(leafContentTypeId); 202 if (leafContentType.getParentMetadata() != null && leafContentType.getParentMetadata().getId() != null) 203 { 204 return leafContentType.getParentMetadata().getId(); 205 } 206 return null; 207 } 208 209 /** Validate the candidate by removing the mixin from the content 210 * @param contentId The id of the content 211 * @param actionId the id of the workflow action 212 * @return The result in a Map 213 * @throws WorkflowException The Workflow Exception 214 * @throws AmetysRepositoryException The Ametys Repository Exception 215 */ 216 @Callable 217 public Map<String, Object> validateCandidate(String contentId, int actionId) throws AmetysRepositoryException, WorkflowException 218 { 219 return _contentHelper.removeMixinType(contentId, HierarchicalReferenceTablesHelper.CANDIDATE_CONTENT_TYPE, actionId); 220 } 221 222 /** 223 * Get the title's properties for edition 224 * @param contentId The id of content being renamed 225 * @return the title's properties 226 */ 227 @Callable 228 public Map<String, Object> getTitleForEdition(String contentId) 229 { 230 Content content = _resolver.resolveById(contentId); 231 232 Map<String, Object> titleInfos = new HashMap<>(); 233 234 MetadataDefinition titleDef = _cTypeHelper.getMetadataDefinition(DefaultContent.METADATA_TITLE, content); 235 titleInfos.put("type", titleDef.getType().name()); 236 titleInfos.put("label", titleDef.getLabel()); 237 238 if (MetadataType.MULTILINGUAL_STRING.equals(titleDef.getType())) 239 { 240 titleInfos.put("value", _contentHelper.getTitleVariants(content)); 241 } 242 else 243 { 244 titleInfos.put("value", _contentHelper.getTitle(content)); 245 } 246 247 return titleInfos; 248 } 249}