001/*
002 *  Copyright 2010 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.clientsideelement;
017
018import java.util.ArrayList;
019import java.util.HashMap;
020import java.util.List;
021import java.util.Map;
022
023import org.apache.avalon.framework.service.ServiceException;
024import org.apache.avalon.framework.service.ServiceManager;
025
026import org.ametys.core.observation.Event;
027import org.ametys.core.observation.ObservationManager;
028import org.ametys.core.ui.Callable;
029import org.ametys.core.ui.ClientSideElement;
030import org.ametys.plugins.repository.AmetysObject;
031import org.ametys.runtime.i18n.I18nizableText;
032import org.ametys.runtime.i18n.I18nizableTextParameter;
033import org.ametys.web.ObservationConstants;
034import org.ametys.web.repository.page.LockablePage;
035import org.ametys.web.repository.page.ModifiablePage;
036import org.ametys.web.repository.page.Page;
037import org.ametys.web.repository.page.SitemapElement;
038import org.ametys.web.repository.page.jcr.AbstractSitemapElement;
039import org.ametys.web.repository.page.jcr.DefaultPage;
040import org.ametys.web.repository.sitemap.Sitemap;
041
042/**
043 * This {@link ClientSideElement} creates a button representing the SEO properties of a page
044 */
045public class PageRobotsClientSideElement extends AbstractSitemapElementClientSideElement
046{
047    private ObservationManager _observationManager;
048    
049    @Override
050    public void service(ServiceManager smanager) throws ServiceException
051    {
052        super.service(smanager);
053        _observationManager = (ObservationManager) smanager.lookup(ObservationManager.ROLE);
054    }
055    
056    /**
057     * Allow/Disallow the robots on a page or sitemap
058     * @param pageIds the selected pages or sitemap
059     * @param exclude true to disallow the robots on the selected pages, false otherwise 
060     * @return the results with successful pages and pages with failure
061     */
062    @Callable (rights = Callable.CHECKED_BY_IMPLEMENTATION)
063    public Map<String, Object> editRobots (List<String> pageIds, boolean exclude)
064    {
065        List<String> allRightIds = new ArrayList<>();
066        List<Map<String, Object>> noRightPages = new ArrayList<>();
067        List<Map<String, Object>> lockedPages = new ArrayList<>();
068        
069        for (String id : pageIds)
070        {
071            AbstractSitemapElement sitemapElmt = _resolver.resolveById(id);
072            
073            if (!hasRight(sitemapElmt))
074            {
075                noRightPages.add(Map.of("id", id, "title", sitemapElmt.getTitle()));
076            }
077            if (sitemapElmt instanceof LockablePage lockablePage && lockablePage.isLocked())
078            {
079                noRightPages.add(Map.of("id", id, "title", sitemapElmt.getTitle()));
080            }
081            else
082            {
083                sitemapElmt.setValue(DefaultPage.METADATA_ROBOTS_DISALLOW, exclude);
084                sitemapElmt.saveChanges();
085                allRightIds.add(id);
086                
087                Map<String, Object> eventParams = new HashMap<>();
088                eventParams.put(sitemapElmt instanceof Sitemap ? ObservationConstants.ARGS_SITEMAP : ObservationConstants.ARGS_SITEMAP_ELEMENT, sitemapElmt);
089                _observationManager.notify(new Event(ObservationConstants.EVENT_ROBOTS_CHANGED, _currentUserProvider.getUser(), eventParams));
090            }
091        } 
092        
093        return Map.of("allright-pages", allRightIds, "noright-pages", noRightPages, "locked-pages", lockedPages);
094    }
095    
096    /**
097     * Get the robots status of given pages or sitemap
098     * @param pageIds The page ids or sitemap id
099     * @return the result
100     */
101    @Callable (rights = Callable.CHECKED_BY_IMPLEMENTATION)
102    public Map<String, Object> getStatus (List<String> pageIds)
103    {
104        Map<String, Object> results = new HashMap<>();
105        
106        results.put("nomodifiable-pages", new ArrayList<>());
107        results.put("noright-pages", new ArrayList<>());
108        results.put("included-pages", new ArrayList<>());
109        results.put("excluded-pages", new ArrayList<>());
110        results.put("parent-excluded-pages", new ArrayList<>());
111    
112        for (String pageId : pageIds)
113        {
114            SitemapElement pageOrSitemap = _resolver.resolveById(pageId);
115            
116            Map<String, Object> pageParams = getSitemapElementDefaultParameters(pageOrSitemap);
117            
118            if (pageOrSitemap instanceof Page && !(pageOrSitemap instanceof ModifiablePage))
119            {
120                pageParams.put("description", getNoModifiablePageDescription((Page) pageOrSitemap));
121
122                @SuppressWarnings("unchecked")
123                List<Map<String, Object>> nomodifiablePages = (List<Map<String, Object>>) results.get("nomodifiable-pages");
124                nomodifiablePages.add(pageParams);
125            }
126            else if (!hasRight(pageOrSitemap))
127            {
128                pageParams.put("description", getNoRightSitemapElementDescription(pageOrSitemap));
129
130                @SuppressWarnings("unchecked")
131                List<Map<String, Object>> norightPages = (List<Map<String, Object>>) results.get("noright-pages");
132                norightPages.add(pageParams);
133            }
134            else
135            {
136                if (_isExcludedFromSEO(pageOrSitemap))
137                {
138                    pageParams.put("description", _getExcludedDescription(pageOrSitemap));
139                    
140                    @SuppressWarnings("unchecked")
141                    List<Map<String, Object>> excludedPages = (List<Map<String, Object>>) results.get("excluded-pages");
142                    excludedPages.add(pageParams);
143                }
144                else if (_isParentExcludedFromSEO(pageOrSitemap))
145                {
146                    pageParams.put("description", _getParentExcludedDescription(pageOrSitemap));
147                    
148                    @SuppressWarnings("unchecked")
149                    List<Map<String, Object>> excludedPages = (List<Map<String, Object>>) results.get("parent-excluded-pages");
150                    excludedPages.add(pageParams);
151                }
152                else
153                {
154                    pageParams.put("description", _getIncludedDescription(pageOrSitemap));
155                    
156                    @SuppressWarnings("unchecked")
157                    List<Map<String, Object>> includedPages = (List<Map<String, Object>>) results.get("included-pages");
158                    includedPages.add(pageParams);
159                    
160                }
161            }
162        }
163        
164        return results;
165    }
166    
167    private I18nizableText _getExcludedDescription (SitemapElement pageOrSitemap)
168    {
169        if (pageOrSitemap instanceof Page)
170        {
171            List<String> i18nParameters = new ArrayList<>();
172            i18nParameters.add(pageOrSitemap.getTitle());
173            
174            I18nizableText ed = (I18nizableText) this._script.getParameters().get("page-excluded-description");
175            return new I18nizableText(ed.getCatalogue(), ed.getKey(), i18nParameters);
176        }
177        else
178        {
179            Map<String, I18nizableTextParameter> i18nParameters = new HashMap<>();
180            i18nParameters.put("title", getSitemapTitle((Sitemap) pageOrSitemap));
181            i18nParameters.put("name", new I18nizableText(pageOrSitemap.getSitemapName()));
182            
183            I18nizableText ed = (I18nizableText) this._script.getParameters().get("sitemap-excluded-description");
184            return new I18nizableText(ed.getCatalogue(), ed.getKey(), i18nParameters);
185        }
186    }
187    
188    private I18nizableText _getParentExcludedDescription (SitemapElement pageOrSitemap)
189    {
190        return _getExcludedDescription(pageOrSitemap);
191    }
192    
193    private I18nizableText _getIncludedDescription (SitemapElement pageOrSitemap)
194    {
195        if (pageOrSitemap instanceof Page)
196        {
197            List<String> i18nParameters = new ArrayList<>();
198            i18nParameters.add(pageOrSitemap.getTitle());
199            
200            I18nizableText ed = (I18nizableText) this._script.getParameters().get("page-included-description");
201            return new I18nizableText(ed.getCatalogue(), ed.getKey(), i18nParameters);
202        }
203        else
204        {
205            Map<String, I18nizableTextParameter> i18nParameters = new HashMap<>();
206            i18nParameters.put("title", getSitemapTitle((Sitemap) pageOrSitemap));
207            i18nParameters.put("name", new I18nizableText(pageOrSitemap.getSitemapName()));
208            
209            I18nizableText ed = (I18nizableText) this._script.getParameters().get("sitemap-included-description");
210            return new I18nizableText(ed.getCatalogue(), ed.getKey(), i18nParameters);
211        }
212    }
213
214    private boolean _isExcludedFromSEO (SitemapElement pageOrSitemap)
215    {
216        return pageOrSitemap.getValueOrDefault(DefaultPage.METADATA_ROBOTS_DISALLOW, false);
217    }
218    
219    private boolean _isParentExcludedFromSEO (SitemapElement pageOrSitemap)
220    {
221        AmetysObject parent = pageOrSitemap.getParent();
222        while (parent != null && parent instanceof SitemapElement sitemapElementParent)
223        {
224            boolean excluded = _isExcludedFromSEO(sitemapElementParent);
225            if (excluded)
226            {
227                return true;
228            }
229            
230            parent = parent.getParent();
231        }
232        
233        return false;
234    }
235}