001/*
002 *  Copyright 2024 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.web.properties.section.page;
017
018import java.util.ArrayList;
019import java.util.HashMap;
020import java.util.HashSet;
021import java.util.LinkedHashMap;
022import java.util.List;
023import java.util.Map;
024import java.util.Set;
025
026import javax.jcr.Node;
027import javax.jcr.NodeIterator;
028import javax.jcr.RepositoryException;
029
030import org.apache.avalon.framework.service.ServiceException;
031import org.apache.avalon.framework.service.ServiceManager;
032import org.apache.avalon.framework.service.Serviceable;
033import org.apache.commons.lang3.LocaleUtils;
034
035import org.ametys.cms.content.references.OutgoingReferencesHelper;
036import org.ametys.cms.properties.section.AbstractDefaultPropertySection;
037import org.ametys.cms.repository.Content;
038import org.ametys.plugins.repository.AmetysObject;
039import org.ametys.plugins.repository.AmetysObjectResolver;
040import org.ametys.plugins.repository.jcr.JCRAmetysObject;
041import org.ametys.web.repository.content.WebContent;
042import org.ametys.web.repository.page.Page;
043
044/**
045 * Section displaying references to the page.
046 */
047public class PageReferencerSection extends AbstractDefaultPropertySection implements Serviceable
048{
049    private AmetysObjectResolver _resolver;
050    
051    public void service(ServiceManager manager) throws ServiceException
052    {
053        _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE);
054    }
055    
056    public boolean supports(AmetysObject ametysObject)
057    {
058        return ametysObject instanceof Page;
059    }
060    
061    @Override
062    protected Map<String, Object> buildData(AmetysObject ametysObject)
063    {
064        Map<String, Object> resultMap = new LinkedHashMap<>();
065        
066        Page page = (Page) ametysObject;
067        resultMap.put("contents", _incomingContents(page));
068        resultMap.put("pages", _incomingPages(page));
069        
070        return resultMap;
071    }
072    
073    private List<Map<String, Object>> _incomingContents(Page page)
074    {
075        List<Map<String, Object>> json = new ArrayList<>();
076        
077        if (page instanceof JCRAmetysObject ametysObject)
078        {
079            // Avoid duplicates
080            Set<Content> refContents = new HashSet<>();
081            
082            try
083            {
084                NodeIterator results = OutgoingReferencesHelper.getContentOutgoingReferences(ametysObject, "page");
085                while (results.hasNext())
086                {
087                    Node node = results.nextNode();
088                    
089                    try
090                    {
091                        Node contentNode = node.getParent()  // go up towards node 'ametys-internal:outgoing-references
092                                               .getParent()  // go up towards node 'ametys-internal:root-outgoing-references
093                                               .getParent(); // go up towards node of the content
094                        Content refContent = _resolver.resolve(contentNode, false);
095
096                        if (refContents.add(refContent))
097                        {
098                            Map<String, Object> contentJson = new HashMap<>();
099                            contentJson.put("id", refContent.getId());
100                            contentJson.put("title", refContent.getTitle(LocaleUtils.toLocale(page.getSitemapName())));
101                            if (refContent instanceof WebContent webContent)
102                            {
103                                contentJson.put(
104                                    "pages",
105                                    webContent.getReferencingPages()
106                                        .stream()
107                                        .map(this::_page2JSON)
108                                        .toList()
109                                );
110                            }
111                            
112                            json.add(contentJson);
113                        }
114                    }
115                    catch (RepositoryException e)
116                    {
117                        getLogger().error("Impossible to get the linked content in the node {}", node.getPath());
118                    }
119                }
120            }
121            catch (RepositoryException e)
122            {
123                // Should not happen
124            }
125        }
126        
127        return json;
128    }
129    
130    private List<Map<String, Object>> _incomingPages(Page page)
131    {
132        String query = "//element(*, ametys:page)[@ametys-internal:type = 'LINK' and @ametys-internal:url='" + page.getId() + "']";
133        return _resolver.<Page>query(query)
134            .stream()
135            .map(this::_page2JSON)
136            .toList();
137    }
138    
139    private Map<String, Object> _page2JSON(Page page)
140    {
141        return Map.of(
142            "id", page.getId(),
143            "title", page.getTitle()
144        );
145    }
146}