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