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        boolean isLocked = page instanceof LockablePage lockablePage && lockablePage.isLocked();
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 && !isLocked);
250        jsonObject.put("modifiable", page instanceof ModifiablePage);
251        jsonObject.put("hasChild", hasChild);
252        jsonObject.put("locked", isLocked);
253        
254        SitemapIcon icon = _sitemapHandler.getIcon(page);
255        
256        jsonObject.put("iconGlyph", icon.getIconGlyph());
257        jsonObject.put("iconDecorator", icon.getIconDecorator());
258        jsonObject.put("iconSmall", icon.getIcon());
259        
260        List<String> decorators = new ArrayList<>();
261        for (SitemapDecorator decorator : _sitemapHandler.getDecorators(page))
262        {
263            decorators.add(decorator.getId());
264        }
265        jsonObject.put("decorators", StringUtils.join(decorators, ","));
266        
267        if (!hasChild)
268        {
269            jsonObject.put("pages", new ArrayList<>());
270        }
271        
272        if (rightsToCheck != null)
273        {
274            jsonObject.put("isAllowed", isCurrentUserAllowed(page, rightsToCheck));
275        }
276        return jsonObject;
277    }
278    
279    /**
280     * Determines if the current user has the requested right on this sitemap element
281     * @param sitemapElement The sitemap element
282     * @param rights The rights to check
283     * @return true if the current user is allowed
284     */
285    public boolean isCurrentUserAllowed(SitemapElement sitemapElement, List<String> rights)
286    {
287        if (rights == null || rights.isEmpty())
288        {
289            return true;
290        }
291        
292        for (String rightId : rights)
293        {
294            if (_rightManager.currentUserHasRight(rightId, sitemapElement) != RightResult.RIGHT_ALLOW)
295            {
296                return false;
297            }
298        }
299        
300        return true;
301    }
302    
303    /**
304     * Get the path of pages which match filter regexp
305     * @param id The id of page or sitemap to start search
306     * @param value the value to match
307     * @return the matching paths
308     */
309    @Callable
310    public List<String> filterPagesByRegExp(String id, String value)
311    {
312        List<String> matchingPaths = new ArrayList<>();
313
314        SitemapElement container = _resolver.resolveById(id);
315        
316        String toMatch = StringUtils.stripAccents(value.toLowerCase()).trim();
317        
318        AmetysObjectIterable< ? extends Page> childrenPages = container.getChildrenPages();
319        for (Page childPage : childrenPages)
320        {
321            _getMatchingPages(childPage, toMatch, matchingPaths);
322        }
323        
324        return matchingPaths;
325    }
326    
327    private void _getMatchingPages(Page page, String value, List<String> matchingPaths)
328    {
329        String title =  StringUtils.stripAccents(page.getTitle().toLowerCase());
330        if (title.contains(value))
331        {
332            matchingPaths.add(page.getPathInSitemap());
333        }
334        
335        AmetysObjectIterable< ? extends Page> childrenPages = page.getChildrenPages();
336        for (Page childPage : childrenPages)
337        {
338            _getMatchingPages (childPage, value, matchingPaths);
339        }
340    }
341    
342    /**
343     * Get the sitemap's decorators
344     * @param siteName the site name
345     * @return the list of decorators
346     */
347    @Callable
348    public List<Map<String, Object>> getDecorators (String siteName)
349    {
350        Site site = _siteManager.getSite(siteName);
351        
352        List<Map<String, Object>> decorators = new ArrayList<>();
353        
354        for (SitemapDecorator decorator : _sitemapHandler.getDecorators(site))
355        {
356            Map<String, Object> object = new HashMap<>();
357            object.put("id", decorator.getId());
358            object.put("label", decorator.getLabel());
359            
360            if (StringUtils.isNotBlank(decorator.getIcon()))
361            {
362                object.put("icon", decorator.getIcon());
363            }
364            if (StringUtils.isNotBlank(decorator.getIconGlyph()))
365            {
366                object.put("iconGlyph", decorator.getIconGlyph());
367            }
368            
369            decorators.add(object);
370        }
371        
372        return decorators;
373    }
374    
375    /**
376     * Get the id of a page from its site name, language and sitemap's path
377     * @param siteName The site name
378     * @param lang The language
379     * @param path the page's path. Can be null to get sitemap's id
380     * @return the page id or null if not found
381     */
382    @Callable
383    public String convertPathToId (String siteName, String lang, String path)
384    {
385        assert lang != null;
386        assert siteName != null;
387
388        Site site = _siteManager.getSite(siteName);
389        assert site != null;
390        
391        Sitemap sitemap = site.getSitemap(lang);
392        assert sitemap != null;
393
394        try
395        {
396            if (path != null)
397            {
398                return sitemap.getChild(path).getId();
399            }
400            else
401            {
402                return sitemap.getId();
403            }
404        }
405        catch (UnknownAmetysObjectException e)
406        {
407            return null;
408        }
409    }
410    
411    
412    /**
413     * Get the user rights on a sitemap
414     * @param sitemap the sitemap
415     * @return The user's rights
416     */
417    protected Set<String> getUserRights (Sitemap sitemap)
418    {
419        UserIdentity user = _currentUserProvider.getUser();
420        return _rightManager.getUserRights(user, sitemap);
421    }
422}