001/*
002 *  Copyright 2016 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.plugins.userdirectory.page;
017
018import java.util.ArrayList;
019import java.util.Arrays;
020import java.util.List;
021import java.util.Map;
022import java.util.Map.Entry;
023import java.util.Set;
024import java.util.SortedSet;
025import java.util.stream.Collectors;
026
027import org.apache.commons.lang3.StringUtils;
028import org.apache.commons.lang3.Strings;
029import org.slf4j.Logger;
030import org.slf4j.LoggerFactory;
031
032import org.ametys.cms.repository.Content;
033import org.ametys.plugins.repository.AmetysObject;
034import org.ametys.plugins.repository.AmetysObjectIterable;
035import org.ametys.plugins.repository.AmetysRepositoryException;
036import org.ametys.plugins.repository.CollectionIterable;
037import org.ametys.plugins.repository.UnknownAmetysObjectException;
038import org.ametys.web.repository.page.Page;
039import org.ametys.web.repository.page.virtual.AbstractConfigurableVirtualPage;
040import org.ametys.web.repository.page.virtual.VirtualPageConfiguration;
041
042
043/**
044 * Page representing a second-level page.
045 */
046public class TransitionalPage extends AbstractConfigurableVirtualPage<TransitionalPageFactory>
047{
048    private static Logger _logger = LoggerFactory.getLogger(TransitionalPage.class);
049    private String _path;
050    private int _initialDepth;
051    private String _prefix;
052    
053    /**
054     * Constructor.
055     * @param root the user directory root page.
056     * @param prefix the page's title.
057     * @param path the path
058     * @param configuration The abstract virtual page configuration
059     * @param scheme The scheme
060     * @param factory The transitional page factory
061     */
062    public TransitionalPage(Page root, VirtualPageConfiguration configuration, String scheme, TransitionalPageFactory factory, String prefix, String path)
063    {
064        super(root, configuration, scheme, factory);
065        
066        _prefix = prefix;
067        _path = path;
068        
069        _initialDepth = _factory.getUserDirectoryPageHandler().getDepth(_root);
070    }
071    
072    @Override
073    public int getDepth() throws AmetysRepositoryException
074    {
075        return _root.getDepth() + _path.split("/").length;
076    }
077
078    @Override
079    public Set<String> getReferers() throws AmetysRepositoryException
080    {
081        return null;
082    }
083
084    @Override
085    public String getTitle() throws AmetysRepositoryException
086    {
087        return StringUtils.upperCase(_prefix);
088    }
089    
090    @Override
091    public String getLongTitle() throws AmetysRepositoryException
092    {
093        return StringUtils.upperCase(_prefix);
094    }
095
096    @Override
097    public AmetysObjectIterable<? extends Page> getChildrenPages() throws AmetysRepositoryException
098    {
099        List<Page> children = new ArrayList<>();
100
101        int depth = _initialDepth - _path.split("/").length;
102        if (depth > 0)
103        {
104            SortedSet<String> transitionalPagesName = _factory.getUserDirectoryPageHandler().getTransitionalPagesName(_root, _factory.getUserDirectoryPageHandler().getName(_path));
105            for (String name : transitionalPagesName)
106            {
107                String pathName = _factory.getUserDirectoryPageHandler().getPathName(name);
108                children.add(_factory.createTransitionalPage(_root, name, _path + "/" + pathName));
109            }
110            
111            Map<String, String> userPagesContent = _factory.getUserDirectoryPageHandler().getUserPagesContent(_root, _factory.getUserDirectoryPageHandler().getName(_path));
112            for (Entry<String, String> entry : userPagesContent.entrySet())
113            {
114                String contentTypeId = _factory.getUserDirectoryPageHandler().getContentTypeId(_root);
115                String classificationAttribute = _factory.getUserDirectoryPageHandler().getClassificationAttribute(_root);
116                Content content;
117                try
118                {
119                    content = _factory.getResolver().resolveById(entry.getValue());
120                }
121                catch (AmetysRepositoryException e)
122                {
123                    // content does not exist, skip to next iteration
124                    break;
125                }
126                if (content == null || !Arrays.asList(content.getTypes()).contains(contentTypeId) || !content.hasValue(classificationAttribute))
127                {
128                    break;
129                }
130                
131                String classificationAttributeValue = _factory.getUserDirectoryPageHandler().getTransformedClassificationValue(_root, content);
132                if (classificationAttributeValue != null && classificationAttributeValue.length() == _path.split("/").length)
133                {
134                    children.add(_factory.getUserPageFactory().createUserPage(_root, content, _path));
135                }
136            }
137        }
138        else
139        {
140            Map<String, String> userPagesContent = _factory.getUserDirectoryPageHandler().getUserPagesContent(_root, _path);
141            for (String contentId : userPagesContent.values())
142            {
143                try
144                {
145                    Content content = _factory.getResolver().resolveById(contentId);
146                    children.add(_factory.getUserPageFactory().createUserPage(_root, content, _path));
147                }
148                catch (UnknownAmetysObjectException e)
149                {
150                    _logger.warn("Content {} does not exist anymore", contentId, e);
151                }
152            }
153        }
154        
155        return new CollectionIterable<>(children);
156    }
157
158    @Override
159    public AmetysObjectIterable< ? extends Page> getChildrenPages(boolean includeInvisiblePage) throws AmetysRepositoryException
160    {
161        if (includeInvisiblePage)
162        {
163            return getChildrenPages();
164        }
165        else
166        {
167            List<Page> children = new ArrayList<>();
168            return new CollectionIterable<>(children);
169        }
170    }
171    
172    @Override
173    public String getPathInSitemap() throws AmetysRepositoryException
174    {
175        String path = StringUtils.lowerCase(_path);
176        return _root.getPathInSitemap() + "/" + path;
177    }
178
179    @SuppressWarnings("unchecked")
180    @Override
181    public <A extends AmetysObject> A getChild(String path) throws AmetysRepositoryException, UnknownAmetysObjectException
182    {
183        if (path.isEmpty())
184        {
185            throw new AmetysRepositoryException("path must be non empty");
186        }
187        
188        String completePath = _path + "/" + path;
189        int depth = _initialDepth - completePath.split("/").length + 1;
190        if (depth > 0)
191        {
192            String namePath = StringUtils.substringAfterLast(completePath, "/");
193            String parentPath = StringUtils.substringBeforeLast(completePath, "/");
194
195            SortedSet<String> transitionalPagesName = _factory.getUserDirectoryPageHandler().getTransitionalPagesName(_root, parentPath);
196            Map<String, String> userPagesContent = _factory.getUserDirectoryPageHandler().getUserPagesContent(_root, parentPath);
197            String name = _factory.getUserDirectoryPageHandler().getName(namePath);
198            if (transitionalPagesName.contains(name))
199            {
200                TransitionalPage page = _factory.createTransitionalPage(_root, name, completePath);
201                return (A) page;
202            }
203            else if (userPagesContent.containsKey(name))
204            {
205                String contentId = userPagesContent.get(name);
206                Content syncContent = _factory.getResolver().resolveById(contentId);
207                UserPage page = _factory.getUserPageFactory().createUserPage(_root, syncContent, parentPath);
208                return (A) page;
209            }
210            else
211            {
212                throw new UnknownAmetysObjectException("No transitional page named " + name + " (full page path " + path + ").");
213            }
214        }
215        else
216        {
217            String userPath = StringUtils.substringBeforeLast(completePath, "/");
218            String contentName = StringUtils.substringAfterLast(completePath, "/");
219            
220            Map<String, String> userPagesContent = _factory.getUserDirectoryPageHandler().getUserPagesContent(_root, userPath);
221            if (userPagesContent.containsKey(contentName))
222            {
223                Content content = _factory.getResolver().resolveById(userPagesContent.get(contentName));
224                
225                UserPage page = _factory.getUserPageFactory().createUserPage(_root, content, userPath);
226                return (A) page;
227            }
228            else
229            {
230                throw new UnknownAmetysObjectException("No user content named " + contentName + " (full page path " + path + ").");
231            }
232        }
233    }
234
235    @SuppressWarnings("unchecked")
236    @Override
237    public AmetysObjectIterable<? extends AmetysObject> getChildren() throws AmetysRepositoryException
238    {
239        return getChildrenPages();
240    }
241
242    @Override
243    public boolean hasChild(String name) throws AmetysRepositoryException
244    {
245        int depth = _initialDepth - _path.split("/").length;
246        if (depth > 0)
247        {
248            SortedSet<String> transitionalPagesName = _factory.getUserDirectoryPageHandler().getTransitionalPagesName(_root, _path);
249            Map<String, String> userPagesContent = _factory.getUserDirectoryPageHandler().getUserPagesContent(_root, _path);
250            return transitionalPagesName.contains(name) || userPagesContent.containsKey(name);
251        }
252        else
253        {
254            Map<String, String> userPagesContent = _factory.getUserDirectoryPageHandler().getUserPagesContent(_root, _path);
255            return userPagesContent.containsKey(name);
256        }
257    }
258    
259    @Override
260    public String getId() throws AmetysRepositoryException
261    {
262        // E.g: udtransitional://path?rootId=...
263        return "udtransitional://" + _path + "?rootId=" + _root.getId();
264    }
265
266    @Override
267    public String getName() throws AmetysRepositoryException
268    {
269        return StringUtils.lowerCase(_prefix);
270    }
271    
272    @SuppressWarnings("unchecked")
273    @Override
274    public Page getParent() throws AmetysRepositoryException
275    {
276        if (_path.split("/").length > 1)
277        {
278            String parentPath = StringUtils.substringBeforeLast(_path, "/");
279            String pathName = parentPath;
280            if (Strings.CS.contains(pathName, "/"))
281            {
282                pathName = StringUtils.substringAfterLast(pathName, "/");
283            }
284            
285            String name = _factory.getUserDirectoryPageHandler().getName(pathName);
286            return _factory.createTransitionalPage(_root, name, parentPath);
287        }
288        else
289        {
290            return _root;
291        }
292    }
293
294    @Override
295    public String getParentPath() throws AmetysRepositoryException
296    {
297        if (_path.split("/").length > 1)
298        {
299            String path = StringUtils.lowerCase(_path);
300            return _root.getPath() + "/" + StringUtils.substringBeforeLast(path, "/");
301        }
302        else
303        {
304            return _root.getPath();
305        }
306    }
307
308    @Override
309    public boolean isVisible() throws AmetysRepositoryException
310    {
311        return false;
312    }
313
314    @Override
315    public Page getChildPageAt(int index) throws UnknownAmetysObjectException, AmetysRepositoryException
316    {
317        return getChildrenPages().stream().collect(Collectors.toList()).get(index);
318    }
319}