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.repository.page;
017
018import java.util.ArrayList;
019import java.util.HashMap;
020import java.util.List;
021import java.util.Map;
022import java.util.Set;
023
024import org.apache.avalon.framework.component.Component;
025import org.apache.avalon.framework.service.ServiceException;
026import org.apache.avalon.framework.service.ServiceManager;
027import org.apache.commons.lang3.StringUtils;
028
029import org.ametys.core.right.RightManager;
030import org.ametys.core.right.RightManager.RightResult;
031import org.ametys.core.ui.Callable;
032import org.ametys.core.user.CurrentUserProvider;
033import org.ametys.core.user.UserIdentity;
034import org.ametys.plugins.repository.AmetysObject;
035import org.ametys.plugins.repository.AmetysObjectIterable;
036import org.ametys.plugins.repository.AmetysObjectResolver;
037import org.ametys.plugins.repository.UnknownAmetysObjectException;
038import org.ametys.web.repository.site.Site;
039import org.ametys.web.repository.site.SiteManager;
040import org.ametys.web.repository.sitemap.Sitemap;
041import org.ametys.web.sitemap.SitemapDecorator;
042import org.ametys.web.sitemap.SitemapDecoratorsHandler;
043import org.ametys.web.sitemap.SitemapIcon;
044
045/**
046 * DAO for manipulating pages
047 */
048public class SitemapDAO extends AbstractSitemapElementsDAO implements Component
049{
050    /** The component's role */
051    public static final String ROLE = SitemapDAO.class.getName();
052    
053    private AmetysObjectResolver _resolver;
054    private RightManager _rightManager;
055    private CurrentUserProvider _currentUserProvider;
056    private SiteManager _siteManager;
057    private SitemapDecoratorsHandler _sitemapHandler;
058    
059    @Override
060    public void service(ServiceManager smanager) throws ServiceException
061    {
062        super.service(smanager);
063        
064        _resolver = (AmetysObjectResolver) smanager.lookup(AmetysObjectResolver.ROLE);
065        _rightManager = (RightManager) smanager.lookup(RightManager.ROLE);
066        _currentUserProvider = (CurrentUserProvider) smanager.lookup(CurrentUserProvider.ROLE);
067        _siteManager = (SiteManager) smanager.lookup(SiteManager.ROLE);
068        _sitemapHandler = (SitemapDecoratorsHandler) smanager.lookup(SitemapDecoratorsHandler.ROLE);
069    }
070    
071    /**
072     * Get sitemap properties
073     * @param sitemapId the sitemap ID
074     * @return the sitemap's properties or null if not found
075     */
076    @Callable
077    public Map<String, Object> getSitemap(String sitemapId)
078    {
079        return getSitemap(sitemapId, null, null);
080    }
081    
082    /**
083     * Get sitemap properties
084     * @param sitemapId the sitemap ID
085     * @param zoneName The optional zone name to limit informations of zones to that zone. Can be null or empty to avoid limitation.
086     * @param zoneItemId The optional zone item identifier to limit informations of zones to that zone item. Can be null or empty to avoid limitation. 
087     * @return the sitemap's properties or null if not found
088     */
089    @Callable
090    public Map<String, Object> getSitemap(String sitemapId, String zoneName, String zoneItemId)
091    {
092        try
093        {
094            Sitemap sitemap = _resolver.resolveById(sitemapId);
095            
096            Map<String, Object> infos = new HashMap<>();
097            
098            infos.put("id", sitemap.getId());
099            infos.put("name", sitemap.getName());
100            infos.put("siteName", sitemap.getSiteName());
101            infos.put("isModifiable", true);
102            infos.put("rights", getUserRights(sitemap));
103            
104            String type = sitemap.getTemplate() != null ? "container" : "node";
105            infos.put("type", type);
106
107            // limitation information
108            if (StringUtils.isNotBlank(zoneName))
109            {
110                infos.put("zoneName", zoneName);
111            }
112            if (StringUtils.isNotBlank(zoneItemId))
113            {
114                infos.put("zoneItemId", zoneItemId);
115            }
116            
117            switch (type)
118            {
119                case "container":
120                    infos.putAll(_sitemapElement2json(sitemap, zoneName, zoneItemId));
121                    break;
122                default:
123            }
124            
125            return infos;
126        }
127        catch (UnknownAmetysObjectException e)
128        {
129            return null;
130        }
131    }
132    
133    /**
134     * Get properties of a site, sitemap or on sites root node
135     * @param siteName the site name. Set to null to get properties of sites root node
136     * @param lang the sitemap language. Set to null to get properties of site node
137     * @return the properties
138     */
139    @Callable
140    public Map<String, Object> getProperties(String siteName, String lang)
141    {
142        Map<String, Object> result = new HashMap<>();
143        
144        if (StringUtils.isEmpty(siteName))
145        {
146            // Get information on root sites node
147            AmetysObject root = _siteManager.getRoot();
148            result.put("id", root.getId());  
149            result.put("name", root.getId());
150        }
151        else if (StringUtils.isEmpty(lang))
152        {
153            // Get properties on site node
154            Site site = _siteManager.getSite(siteName);
155            result.put("id", site.getId());  
156            result.put("name", site.getName());
157            result.put("title", site.getTitle());
158        }
159        else
160        {
161            // Get properties on sitemap node
162            result = getSitemapProperties(siteName, lang, null);
163        }
164                
165        return result;
166    }
167    
168    /**
169     * Get the sitemap properties as JSON object
170     * @param siteName the site name. Set to null to get properties of sites root node
171     * @param lang the sitemap language. Set to null to get properties of site node
172     * @param rights If not null, the sitemap properties will contain a 'isAllowed' property based on user rights. Can be null.
173     * @return the sitemap properties
174     */
175    @Callable
176    public Map<String, Object> getSitemapProperties(String siteName, String lang, List<String> rights)
177    {
178        Site site = _siteManager.getSite(siteName);
179        Sitemap sitemap = site.getSitemap(lang);
180        
181        return getSitemapProperties(sitemap, rights);
182    }
183    
184    /**
185     * Get the sitemap properties into a JSON object
186     * @param sitemap The sitemap
187     * @param rightsToCheck If not null, the sitemap properties will contain a 'isAllowed' property based on user rights. Can be null.
188     * @return the sitemap properties
189     */
190    public Map<String, Object> getSitemapProperties(Sitemap sitemap, List<String> rightsToCheck)
191    {
192        Map<String, Object> jsonObject = new HashMap<>();
193        
194        jsonObject.put("id", sitemap.getId());
195        jsonObject.put("name", sitemap.getName());
196        jsonObject.put("lang", sitemap.getName());
197        jsonObject.put("siteName", sitemap.getSiteName());
198        
199        if (rightsToCheck != null)
200        {
201            jsonObject.put("isAllowed", isCurrentUserAllowed(sitemap, rightsToCheck));
202        }
203        
204        return jsonObject;
205    }
206    
207    /**
208     * Get the properties of a page in order to display it into a sitemap tree
209     * @param pageId The page's id
210     * @return The page's properties
211     */
212    @Callable
213    public Map<String, Object> getPageProperties(String pageId)
214    {
215        return getPageProperties((Page) _resolver.resolveById(pageId));
216    }
217    
218    /**
219     * Get the properties of a page in order to display it into a sitemap tree
220     * @param page The page
221     * @return The page's properties
222     */
223    public Map<String, Object> getPageProperties(Page page)
224    {
225        return getPageProperties(page, null);
226    }
227    
228    /**
229     * Get the properties of a page in order to display it into a sitemap tree
230     * @param page The page
231     * @param rightsToCheck If not null, the page properties will contain a 'isAllowed' property based on user rights
232     * @return The page's properties
233     */
234    public Map<String, Object> getPageProperties(Page page, List<String> rightsToCheck)
235    {
236        boolean hasChild = page.getChildrenPages().iterator().hasNext();
237        
238        Map<String, Object> jsonObject = new HashMap<>();
239        
240        jsonObject.put("id", page.getId());
241        jsonObject.put("name", page.getName());
242        jsonObject.put("siteName", page.getSiteName());
243        jsonObject.put("lang", page.getSitemapName());
244        jsonObject.put("title", page.getTitle());
245        jsonObject.put("longTitle", page.getLongTitle());   
246        jsonObject.put("type", page.getType());
247        jsonObject.put("template", page.getTemplate());
248        jsonObject.put("path", page.getPathInSitemap());
249        jsonObject.put("moveable", page instanceof MoveablePage);
250        jsonObject.put("modifiable", page instanceof ModifiablePage);
251        jsonObject.put("hasChild", hasChild);
252        
253        SitemapIcon icon = _sitemapHandler.getIcon(page);
254        
255        jsonObject.put("iconGlyph", icon.getIconGlyph());
256        jsonObject.put("iconDecorator", icon.getIconDecorator());
257        jsonObject.put("iconSmall", icon.getIcon());
258        
259        List<String> decorators = new ArrayList<>();
260        for (SitemapDecorator decorator : _sitemapHandler.getDecorators(page))
261        {
262            decorators.add(decorator.getId());
263        }
264        jsonObject.put("decorators", StringUtils.join(decorators, ","));
265        
266        if (!hasChild)
267        {
268            jsonObject.put("pages", new ArrayList<>());
269        }
270        
271        if (rightsToCheck != null)
272        {
273            jsonObject.put("isAllowed", isCurrentUserAllowed(page, rightsToCheck));
274        }
275        return jsonObject;
276    }
277    
278    /**
279     * Determines if the current user has the requested right on this sitemap element
280     * @param sitemapElement The sitemap element
281     * @param rights The rights to check
282     * @return true if the current user is allowed
283     */
284    public boolean isCurrentUserAllowed(SitemapElement sitemapElement, List<String> rights)
285    {
286        if (rights == null || rights.isEmpty())
287        {
288            return true;
289        }
290        
291        for (String rightId : rights)
292        {
293            if (_rightManager.currentUserHasRight(rightId, sitemapElement) != RightResult.RIGHT_ALLOW)
294            {
295                return false;
296            }
297        }
298        
299        return true;
300    }
301    
302    /**
303     * Get the path of pages which match filter regexp
304     * @param id The id of page or sitemap to start search
305     * @param value the value to match
306     * @return the matching paths
307     */
308    @Callable
309    public List<String> filterPagesByRegExp(String id, String value)
310    {
311        List<String> matchingPaths = new ArrayList<>();
312
313        SitemapElement container = _resolver.resolveById(id);
314        
315        String toMatch = StringUtils.stripAccents(value.toLowerCase()).trim();
316        
317        AmetysObjectIterable< ? extends Page> childrenPages = container.getChildrenPages();
318        for (Page childPage : childrenPages)
319        {
320            _getMatchingPages(childPage, toMatch, matchingPaths);
321        }
322        
323        return matchingPaths;
324    }
325    
326    private void _getMatchingPages(Page page, String value, List<String> matchingPaths)
327    {
328        String title =  StringUtils.stripAccents(page.getTitle().toLowerCase());
329        if (title.contains(value))
330        {
331            matchingPaths.add(page.getPathInSitemap());
332        }
333        
334        AmetysObjectIterable< ? extends Page> childrenPages = page.getChildrenPages();
335        for (Page childPage : childrenPages)
336        {
337            _getMatchingPages (childPage, value, matchingPaths);
338        }
339    }
340    
341    /**
342     * Get the sitemap's decorators
343     * @param siteName the site name
344     * @return the list of decorators
345     */
346    @Callable
347    public List<Map<String, Object>> getDecorators (String siteName)
348    {
349        Site site = _siteManager.getSite(siteName);
350        
351        List<Map<String, Object>> decorators = new ArrayList<>();
352        
353        for (SitemapDecorator decorator : _sitemapHandler.getDecorators(site))
354        {
355            Map<String, Object> object = new HashMap<>();
356            object.put("id", decorator.getId());
357            object.put("label", decorator.getLabel());
358            
359            if (StringUtils.isNotBlank(decorator.getIcon()))
360            {
361                object.put("icon", decorator.getIcon());
362            }
363            if (StringUtils.isNotBlank(decorator.getIconGlyph()))
364            {
365                object.put("iconGlyph", decorator.getIconGlyph());
366            }
367            
368            decorators.add(object);
369        }
370        
371        return decorators;
372    }
373    
374    /**
375     * Get the id of a page from its site name, language and sitemap's path
376     * @param siteName The site name
377     * @param lang The language
378     * @param path the page's path. Can be null to get sitemap's id
379     * @return the page id or null if not found
380     */
381    @Callable
382    public String convertPathToId (String siteName, String lang, String path)
383    {
384        assert lang != null;
385        assert siteName != null;
386
387        Site site = _siteManager.getSite(siteName);
388        assert site != null;
389        
390        Sitemap sitemap = site.getSitemap(lang);
391        assert sitemap != null;
392
393        try
394        {
395            if (path != null)
396            {
397                return sitemap.getChild(path).getId();
398            }
399            else
400            {
401                return sitemap.getId();
402            }
403        }
404        catch (UnknownAmetysObjectException e)
405        {
406            return null;
407        }
408    }
409    
410    
411    /**
412     * Get the user rights on a sitemap
413     * @param sitemap the sitemap
414     * @return The user's rights
415     */
416    protected Set<String> getUserRights (Sitemap sitemap)
417    {
418        UserIdentity user = _currentUserProvider.getUser();
419        return _rightManager.getUserRights(user, sitemap);
420    }
421}