001/*
002 *  Copyright 2015 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.cache;
017
018import java.util.ArrayList;
019import java.util.Collection;
020import java.util.Iterator;
021import java.util.List;
022
023import org.apache.avalon.framework.component.Component;
024import org.apache.avalon.framework.logger.AbstractLogEnabled;
025import org.apache.avalon.framework.service.ServiceException;
026import org.apache.avalon.framework.service.ServiceManager;
027import org.apache.avalon.framework.service.Serviceable;
028
029import org.ametys.cms.repository.Content;
030import org.ametys.core.right.RightManager;
031import org.ametys.plugins.repository.AmetysObjectIterable;
032import org.ametys.web.inputdata.InputData;
033import org.ametys.web.inputdata.InputDataExtensionPoint;
034import org.ametys.web.repository.page.Page;
035import org.ametys.web.repository.page.Page.PageType;
036import org.ametys.web.repository.page.Zone;
037import org.ametys.web.repository.page.ZoneItem;
038import org.ametys.web.repository.page.ZoneItem.ZoneType;
039import org.ametys.web.service.Service;
040import org.ametys.web.service.ServiceExtensionPoint;
041import org.ametys.web.site.SiteConfigurationExtensionPoint;
042
043/**
044 * Helper component providing status of pages.
045 */
046public class PageHelper extends AbstractLogEnabled implements Component, Serviceable
047{
048    /** The component role. */
049    public static final String ROLE = PageHelper.class.getName();
050    
051    private ServiceExtensionPoint _serviceExtPt;
052    private RightManager _rightManager;
053    private InputDataExtensionPoint _inputDataExtensionPoint;
054    private SiteConfigurationExtensionPoint _siteConfiguration;
055    
056    @Override
057    public void service(ServiceManager serviceManager) throws ServiceException
058    {
059        _serviceExtPt = (ServiceExtensionPoint) serviceManager.lookup(ServiceExtensionPoint.ROLE);
060        _rightManager = (RightManager) serviceManager.lookup(RightManager.ROLE);
061        _inputDataExtensionPoint = (InputDataExtensionPoint) serviceManager.lookup(InputDataExtensionPoint.ROLE);
062        _siteConfiguration = (SiteConfigurationExtensionPoint) serviceManager.lookup(SiteConfigurationExtensionPoint.ROLE);
063    }
064    
065    /**
066     * Tests if a page is cacheable, i.e:<ul>
067     * <li>its access is not restricted</li>
068     * <li>all its page elements are cachable</li>
069     * </ul>
070     * @param page The page to test.
071     * @return true if the page is cachable, false otherwise.
072     */
073    public boolean isCacheable(Page page)
074    {
075        if (!_rightManager.hasAnonymousReadAccess(page))
076        {
077            // never cache a private page
078            return false;
079        }
080        
081        if (page.getType() != PageType.CONTAINER)
082        {
083            // makes no sense to cache a Node or link page
084            return false;
085        }
086        
087        boolean isCacheable = true;
088        AmetysObjectIterable<? extends Zone> zones = page.getZones();
089        Iterator<? extends Zone> itZ = zones.iterator();
090        
091        // test each service of the page
092        while (isCacheable && itZ.hasNext())
093        {
094            Zone zone = itZ.next();
095            AmetysObjectIterable<? extends ZoneItem> zoneItems = zone.getZoneItems();
096            Iterator<? extends ZoneItem> itZI = zoneItems.iterator();
097            
098            while (isCacheable && itZI.hasNext())
099            {
100                ZoneItem zoneItem = itZI.next();
101                if (zoneItem.getType() == ZoneType.SERVICE)
102                {
103                    Service service = _serviceExtPt.getExtension(zoneItem.getServiceId());
104                    try
105                    {
106                        isCacheable = service != null && service.isCacheable(page, zoneItem);
107                    }
108                    catch (Exception e)
109                    {
110                        // Ignore
111                    }
112                }
113            }
114        }
115        
116        // Test each inputdata
117        if (isCacheable)
118        {
119            Collection<String> ids = _inputDataExtensionPoint.getExtensionsIds();
120            Iterator<String> it = ids.iterator();
121            while (isCacheable && it.hasNext())
122            {
123                String id = it.next();
124                InputData inputData = _inputDataExtensionPoint.getExtension(id);
125                isCacheable = inputData.isCacheable(page.getSite(), page);
126            }
127        }
128        
129        return isCacheable;
130    }
131    
132    /**
133     * Determines if a captcha is required on forms of the page
134     * @param page The page to test
135     * @return  true if a captcha is required
136     */
137    public boolean isCaptchaRequired (Page page)
138    {
139        String siteName = page.getSiteName();
140        
141        String captchaPolicy = _siteConfiguration.getValueAsString(siteName, "display-captcha-policy");
142        
143        if (captchaPolicy == null || "restricted".equals(captchaPolicy)) 
144        {
145            // Display captcha on public page only
146            return _rightManager.hasAnonymousReadAccess(page); 
147        }
148        
149        return "always".equals(captchaPolicy);
150    }
151
152    /**
153     * Get all the contents inside a page
154     * @param page page to search
155     * @return list of contents in this page
156     */
157    public List<Content> getAllContents (Page page)
158    {
159        List<Content> result = new ArrayList<>();
160        AmetysObjectIterable< ? extends Zone> zones = page.getZones();
161        for (Zone zone : zones)
162        {
163            AmetysObjectIterable< ? extends ZoneItem> zoneItems = zone.getZoneItems();
164            for (ZoneItem zoneItem : zoneItems)
165            {
166                if (ZoneType.CONTENT.equals(zoneItem.getType()))
167                {
168                    Content content = zoneItem.getContent();
169                    result.add(content);
170                }
171            }
172        }
173        return result;
174    }
175
176}