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.ArrayList; 019import java.util.Arrays; 020import java.util.Collections; 021import java.util.HashMap; 022import java.util.List; 023import java.util.Map; 024import java.util.stream.Collectors; 025 026import org.apache.avalon.framework.service.ServiceException; 027import org.apache.avalon.framework.service.ServiceManager; 028import org.apache.commons.collections.CollectionUtils; 029 030import org.ametys.cms.clientsideelement.relations.SetContentMetadataClientSideElement; 031import org.ametys.cms.contenttype.ContentType; 032import org.ametys.cms.contenttype.ContentTypeExtensionPoint; 033import org.ametys.cms.contenttype.MetadataDefinition; 034import org.ametys.cms.repository.Content; 035import org.ametys.core.ui.Callable; 036import org.ametys.plugins.repository.AmetysRepositoryException; 037import org.ametys.runtime.parameter.Validator; 038 039/** 040 * Set the "parent" metadata of a simple content 041 */ 042public class SetParentContentClientSideElement extends SetContentMetadataClientSideElement 043{ 044 /** The helper component for hierarchical simple contents */ 045 protected HierarchicalReferenceTablesHelper _hierarchicalSimpleContentsHelper; 046 /** The extension point for content types */ 047 protected ContentTypeExtensionPoint _contentTypeEP; 048 049 @Override 050 public void service(ServiceManager manager) throws ServiceException 051 { 052 super.service(manager); 053 _hierarchicalSimpleContentsHelper = (HierarchicalReferenceTablesHelper) manager.lookup(HierarchicalReferenceTablesHelper.ROLE); 054 _contentTypeEP = (ContentTypeExtensionPoint) manager.lookup(ContentTypeExtensionPoint.ROLE); 055 } 056 057 /** 058 * Tells if the given simple contents can have their parent metadata changed for the given new simple content parent. 059 * @param contentIdsToMove The ids of the simple contents willing to change their parent metadata 060 * @param newParentContentId The id of the new parent simple content. Can be "root" if it is the root of simple contents 061 * @param leafContentTypeId If newParentContentId is equal to "root", is the id of the content type of the leaves of the tree. Otherwise, must be null 062 * @return A map with key 'validContents' and key 'invalidContents' 063 */ 064 @Callable 065 public Map<String, Object> areValidMoves(List<String> contentIdsToMove, String newParentContentId, String leafContentTypeId) 066 { 067 Map<String, Object> result = new HashMap<>(); 068 List<Map<String, String>> validContents = new ArrayList<>(); 069 result.put("validContents", validContents); 070 List<String> invalidContents = new ArrayList<>(); 071 result.put("invalidContents", invalidContents); 072 073 if ("root".equals(newParentContentId)) 074 { 075 ContentType leafContentType = _contentTypeEP.getExtension(leafContentTypeId); 076 String topLevelType = _hierarchicalSimpleContentsHelper.getTopLevelType(leafContentType).getId(); 077 078 for (String contentIdToMove : contentIdsToMove) 079 { 080 try 081 { 082 Content contentToMove = _resolver.resolveById(contentIdToMove); 083 MetadataDefinition parentMetadatadef = _getParentMetadataDef(contentToMove); 084 if (parentMetadatadef == null) 085 { 086 invalidContents.add(contentIdToMove); 087 break; 088 } 089 090 // 1) As move towards the root node means removing the "parent" meta, check it is not mandatory 091 Validator validator = parentMetadatadef.getValidator(); 092 if (validator != null && (Boolean) validator.getConfiguration().get("mandatory")) 093 { 094 invalidContents.add(contentIdToMove); 095 break; 096 } 097 098 // 2) Check the content is a potential child of root node, i.e. has good content type 099 if (Arrays.asList(contentToMove.getTypes()).contains(topLevelType)) 100 { 101 validContents.add(_validContentToMap(contentToMove, Collections.singletonList(topLevelType))); 102 } 103 else 104 { 105 invalidContents.add(contentIdToMove); 106 } 107 } 108 catch (AmetysRepositoryException e) 109 { 110 getLogger().error("An error occured while retrieving the content to move.", e); 111 invalidContents.add(contentIdToMove); 112 } 113 } 114 } 115 else 116 { 117 Content newParent; 118 try 119 { 120 newParent = _resolver.resolveById(newParentContentId); 121 } 122 catch (AmetysRepositoryException e) 123 { 124 getLogger().error("An error occured while retrieving the new parent content.", e); 125 result.put("error", "unknown-parent"); 126 return result; 127 } 128 List<String> childContentTypes = _hierarchicalSimpleContentsHelper.getChildContentTypes(newParent).stream() 129 .map(ContentType::getId) 130 .collect(Collectors.toList()); 131 for (String contentIdToMove : contentIdsToMove) 132 { 133 try 134 { 135 Content contentToMove = _resolver.resolveById(contentIdToMove); 136 if (CollectionUtils.containsAny(Arrays.asList(contentToMove.getTypes()), childContentTypes)) 137 { 138 // The content types of the content is valid with the new parent 139 Map<String, String> validContent = _validContentToMap(contentToMove, childContentTypes); 140 validContents.add(validContent); 141 } 142 else 143 { 144 invalidContents.add(contentIdToMove); 145 } 146 } 147 catch (AmetysRepositoryException e) 148 { 149 getLogger().error("An error occured while retrieving the content to move.", e); 150 invalidContents.add(contentIdToMove); 151 } 152 } 153 } 154 155 return result; 156 } 157 158 private MetadataDefinition _getParentMetadataDef(Content content) 159 { 160 for (String cTypeId : content.getTypes()) 161 { 162 ContentType cType = _contentTypeEP.getExtension(cTypeId); 163 MetadataDefinition parentMetadata = cType.getParentMetadata(); 164 if (parentMetadata != null) 165 { 166 return parentMetadata; 167 } 168 } 169 170 return null; 171 } 172 173 private Map<String, String> _validContentToMap(Content validContent, List<String> childContentTypes) 174 { 175 Map<String, String> contentMap = new HashMap<>(); 176 contentMap.put("id", validContent.getId()); 177 178 List<String> types = Arrays.asList(validContent.getTypes()); 179 for (String childContentTypeId : childContentTypes) 180 { 181 if (types.contains(childContentTypeId)) 182 { 183 ContentType childContentType = _contentTypeEP.getExtension(childContentTypeId); 184 contentMap.put("parentMetadataName", childContentType.getParentMetadata().getName()); 185 } 186 } 187 188 contentMap.put("parentMetadataValue", _hierarchicalSimpleContentsHelper.getParent(validContent)); 189 190 return contentMap; 191 } 192}