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