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}