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.Collections;
020import java.util.Locale;
021import java.util.Map;
022import java.util.Set;
023
024import org.apache.commons.lang.StringUtils;
025
026import org.ametys.cms.repository.Content;
027import org.ametys.core.group.GroupIdentity;
028import org.ametys.core.right.ProfileAssignmentStorage.AnonymousOrAnyConnectedKeys;
029import org.ametys.core.right.ProfileAssignmentStorage.UserOrGroup;
030import org.ametys.core.right.RightManager;
031import org.ametys.core.user.UserIdentity;
032import org.ametys.plugins.contentio.synchronize.SynchronizableContentsCollection;
033import org.ametys.plugins.contentio.synchronize.SynchronizableContentsCollectionDAO;
034import org.ametys.plugins.contentio.synchronize.SynchronizableContentsCollectionHelper;
035import org.ametys.plugins.explorer.resources.ResourceCollection;
036import org.ametys.plugins.repository.ACLAmetysObject;
037import org.ametys.plugins.repository.AmetysObject;
038import org.ametys.plugins.repository.AmetysObjectIterable;
039import org.ametys.plugins.repository.AmetysObjectResolver;
040import org.ametys.plugins.repository.AmetysRepositoryException;
041import org.ametys.plugins.repository.CollectionIterable;
042import org.ametys.plugins.repository.UnknownAmetysObjectException;
043import org.ametys.plugins.repository.data.holder.ModelAwareDataHolder;
044import org.ametys.plugins.repository.data.holder.ModelLessDataHolder;
045import org.ametys.plugins.repository.data.holder.impl.DefaultModelLessDataHolder;
046import org.ametys.plugins.repository.data.repositorydata.RepositoryData;
047import org.ametys.plugins.repository.data.repositorydata.impl.MemoryRepositoryData;
048import org.ametys.plugins.repository.data.type.RepositoryModelItemType;
049import org.ametys.plugins.userdirectory.UserDirectoryPageHandler;
050import org.ametys.runtime.plugin.component.AbstractThreadSafeComponentExtensionPoint;
051import org.ametys.web.repository.page.Page;
052import org.ametys.web.repository.page.UnknownZoneException;
053import org.ametys.web.repository.page.Zone;
054import org.ametys.web.repository.site.Site;
055import org.ametys.web.repository.sitemap.Sitemap;
056import org.ametys.web.service.ServiceExtensionPoint;
057import org.ametys.web.skin.Skin;
058import org.ametys.web.skin.SkinsManager;
059
060/**
061 * Page representing a second-level page.
062 */
063public class UserPage implements Page, ACLAmetysObject
064{
065    private static final String __USER_PAGE_TEMPLATE = "user-page";
066    
067    private Page _root;
068    private int _initialDepth;
069    private String _title;
070    private AmetysObjectResolver _resolver;
071    private UserDirectoryPageHandler _userDirectoryPageHandler;
072    private SynchronizableContentsCollectionDAO _syncContentsCollectionDAO;
073    private SkinsManager _skinsManager;
074    private String _path;
075    private Content _syncContent;
076    private SynchronizableContentsCollectionHelper _sccHelper;
077
078    private AbstractThreadSafeComponentExtensionPoint<RepositoryModelItemType> _pageDataTypeExtensionPoint;
079    private AbstractThreadSafeComponentExtensionPoint<RepositoryModelItemType> _zoneDataTypeExtensionPoint;
080    private ServiceExtensionPoint _serviceExtensionPoint;
081    private AbstractThreadSafeComponentExtensionPoint<RepositoryModelItemType> _zoneItemDataTypeExtensionPoint;
082    
083    /**
084     * Constructor.
085     * @param root the root page.
086     * @param syncContent the synchronized content
087     * @param path the path
088     * @param resolver the {@link AmetysObjectResolver}.
089     * @param userDirectoryPageHandler the user directory page handler
090     * @param syncContentsCollectionDAO The DAO for synchronizable collections
091     * @param skinsManager the skins manager
092     * @param sccHelper the SCC helper
093     * @param pageDataTypeExtensionPoint the extension point with available data types for pages
094     * @param zoneDataTypeExtensionPoint the extension point with available data types for zones
095     * @param serviceExtensionPoint the service extension point
096     * @param zoneItemDataTypeExtensionPoint the extension point with available data types for zone items
097     */
098    public UserPage(Page root, Content syncContent, String path, AmetysObjectResolver resolver, UserDirectoryPageHandler userDirectoryPageHandler, SynchronizableContentsCollectionDAO syncContentsCollectionDAO, SkinsManager skinsManager, SynchronizableContentsCollectionHelper sccHelper, AbstractThreadSafeComponentExtensionPoint<RepositoryModelItemType> pageDataTypeExtensionPoint, AbstractThreadSafeComponentExtensionPoint<RepositoryModelItemType> zoneDataTypeExtensionPoint, ServiceExtensionPoint serviceExtensionPoint, AbstractThreadSafeComponentExtensionPoint<RepositoryModelItemType> zoneItemDataTypeExtensionPoint)
099    {
100        _root = root;
101        _path = path;
102        _resolver = resolver;
103        _userDirectoryPageHandler = userDirectoryPageHandler;
104        _syncContentsCollectionDAO = syncContentsCollectionDAO;
105        _skinsManager = skinsManager;
106        _syncContent = syncContent;
107        _sccHelper = sccHelper;
108        
109        _title = _syncContent.getTitle(new Locale(root.getSitemapName()));
110        _initialDepth = _userDirectoryPageHandler.getDepth(_root);
111
112        _pageDataTypeExtensionPoint = pageDataTypeExtensionPoint;
113        _zoneDataTypeExtensionPoint = zoneDataTypeExtensionPoint;
114        _serviceExtensionPoint = serviceExtensionPoint;
115        _zoneItemDataTypeExtensionPoint = zoneItemDataTypeExtensionPoint;
116    }
117
118    /**
119     * Compute a page id
120     * @param path The path
121     * @param rootId The root page id
122     * @param contentId The content id
123     * @return The id
124     */
125    public static String getId(String path, String rootId, String contentId)
126    {
127        // E.g: uduser://path?rootId=...&contentId=...
128        return "uduser://" + (StringUtils.isEmpty(path) ? "_root" : path) + "?rootId=" + rootId + "&contentId=" + contentId;
129    }
130    
131    /**
132     * Returns the associated synchronizable {@link Content}.
133     * @return the associated synchronizable {@link Content}.
134     */
135    public Content getSyncContent()
136    {
137        return _syncContent;
138    }
139    
140    
141    public int getDepth() throws AmetysRepositoryException
142    {
143        return _root.getDepth() + _initialDepth + 1;
144    }
145
146    
147    public Set<String> getReferers() throws AmetysRepositoryException
148    {
149        return null;
150    }
151
152    
153    public ResourceCollection getRootAttachments() throws AmetysRepositoryException
154    {
155        return null;
156    }
157
158    
159    public String getTemplate() throws AmetysRepositoryException
160    {
161        Skin skin = _skinsManager.getSkin(getSite().getSkinId());
162        
163        if (skin.getTemplate(__USER_PAGE_TEMPLATE) != null)
164        {
165            return __USER_PAGE_TEMPLATE;
166        }
167        
168        return "page"; 
169    }
170
171    
172    public String getTitle() throws AmetysRepositoryException
173    {
174        return _title;
175    }
176    
177    
178    public String getLongTitle() throws AmetysRepositoryException
179    {
180        return _title;
181    }
182
183    
184    public PageType getType() throws AmetysRepositoryException
185    {
186        return PageType.CONTAINER;
187    }
188
189    
190    public String getURL() throws AmetysRepositoryException
191    {
192        throw new UnsupportedOperationException("#getURL is not supported on virtual user pages");
193    }
194
195    
196    public LinkType getURLType() throws AmetysRepositoryException
197    {
198        throw new UnsupportedOperationException("#getURLType is not supported on virtual user pages");
199    }
200
201    
202    public Zone getZone(String name) throws UnknownZoneException, AmetysRepositoryException
203    {
204        if (!"default".equals(name))
205        {
206            throw new IllegalArgumentException("Only the zone named 'default' is actually supported on virtual user pages.");
207        }
208        
209        return new UserZone(this, _zoneDataTypeExtensionPoint, _zoneItemDataTypeExtensionPoint);
210    }
211
212    
213    public AmetysObjectIterable< ? extends Zone> getZones() throws AmetysRepositoryException
214    {
215        ArrayList<Zone> zones = new ArrayList<>();
216        zones.add(new UserZone(this, _zoneDataTypeExtensionPoint, _zoneItemDataTypeExtensionPoint));
217        return new CollectionIterable<>(zones);
218    }
219
220    
221    public boolean hasZone(String name) throws AmetysRepositoryException
222    {
223        return "default".equals(name);
224    }
225
226    
227    public AmetysObjectIterable<? extends Page> getChildrenPages() throws AmetysRepositoryException
228    {
229        ArrayList<Page> children = new ArrayList<>();
230        return new CollectionIterable<>(children);
231    }
232
233    
234    public String getPathInSitemap() throws AmetysRepositoryException
235    {
236        if (_path.equals("_root"))
237        {
238            return _root.getPathInSitemap() + "/" + getName();
239        }
240        else
241        {
242            String path = StringUtils.lowerCase(_path);
243            return _root.getPathInSitemap() + "/" + path + "/" + getName();
244        }
245    }
246
247    
248    public Site getSite() throws AmetysRepositoryException
249    {
250        return _root.getSite();
251    }
252
253    
254    public String getSiteName() throws AmetysRepositoryException
255    {
256        return _root.getSiteName();
257    }
258
259    
260    public Sitemap getSitemap() throws AmetysRepositoryException
261    {
262        return _root.getSitemap();
263    }
264
265    
266    public String getSitemapName() throws AmetysRepositoryException
267    {
268        return _root.getSitemapName();
269    }
270
271    
272    public <A extends AmetysObject> A getChild(String path) throws AmetysRepositoryException, UnknownAmetysObjectException
273    {
274        if (path.isEmpty())
275        {
276            throw new AmetysRepositoryException("path must be non empty");
277        }
278        
279        return null;
280    }
281
282    @SuppressWarnings("unchecked")
283    
284    public AmetysObjectIterable<? extends AmetysObject> getChildren() throws AmetysRepositoryException
285    {
286        return getChildrenPages();
287    }
288
289    
290    public boolean hasChild(String name) throws AmetysRepositoryException
291    {
292        return false;
293    }
294    
295    
296    public String getId() throws AmetysRepositoryException
297    {
298        return getId(_path, _root.getId(), _syncContent.getId());
299    }
300
301    
302    public String getName() throws AmetysRepositoryException
303    {
304        return _syncContent.getName();
305    }
306    
307    @SuppressWarnings("unchecked")
308    
309    public Page getParent() throws AmetysRepositoryException
310    {
311        if (_initialDepth > 0)
312        {
313            String pathName = StringUtils.substringAfterLast(_path, "/");
314            String name = _userDirectoryPageHandler.getName(pathName);
315            return new TransitionalPage(_root, name, _path, _resolver, _userDirectoryPageHandler, _syncContentsCollectionDAO, _skinsManager, _sccHelper, _pageDataTypeExtensionPoint, _zoneDataTypeExtensionPoint, _serviceExtensionPoint, _zoneItemDataTypeExtensionPoint);
316        }
317        else
318        {
319            return _root;
320        }
321    }
322
323    
324    public String getParentPath() throws AmetysRepositoryException
325    {
326        if (_initialDepth > 0)
327        {
328            String path = StringUtils.lowerCase(_path);
329            return _root.getPath() + "/" + path;
330        }
331        else
332        {
333            return _root.getPath();
334        }
335    }
336
337    
338    public String getPath() throws AmetysRepositoryException
339    {
340        return getParentPath() + "/" + getName();
341    }
342
343    public ModelLessDataHolder getDataHolder()
344    {
345        RepositoryData repositoryData = new MemoryRepositoryData(getName());
346        return new DefaultModelLessDataHolder(_pageDataTypeExtensionPoint, repositoryData);
347    }
348
349    
350    public Set<String> getTags() throws AmetysRepositoryException
351    {
352        return Collections.emptySet();
353    }
354
355    
356    public AmetysObjectIterable< ? extends Page> getChildrenPages(boolean includeInvisiblePage) throws AmetysRepositoryException
357    {
358        ArrayList<Page> children = new ArrayList<>();
359        return new CollectionIterable<>(children);
360    }
361
362    
363    public boolean isVisible() throws AmetysRepositoryException
364    {
365        return false;
366    }
367
368    
369    public Page getChildPageAt(int index) throws UnknownAmetysObjectException, AmetysRepositoryException
370    {
371        throw new UnknownAmetysObjectException("There is no child for user page");
372    }
373
374    public Map<AnonymousOrAnyConnectedKeys, Set<String>> getProfilesForAnonymousAndAnyConnectedUser()
375    {
376        Set<String> collectionIds = _sccHelper.getSynchronizableCollectionIds(_syncContent);
377        for (String collectionId : collectionIds)
378        {
379            SynchronizableContentsCollection collection = _syncContentsCollectionDAO.getSynchronizableContentsCollection(collectionId);
380            if (collection != null)
381            {
382                String restrictedField = collection.getRestrictedField();
383                if (!StringUtils.isEmpty(restrictedField))
384                {
385                    Boolean restricted = _syncContent.getValue(restrictedField);
386                    if (restricted != null && restricted.booleanValue())
387                    {
388                        return Map.of(AnonymousOrAnyConnectedKeys.ANONYMOUS_DENIED, Set.of(RightManager.READER_PROFILE_ID));
389                    }
390                }
391            }
392        }
393        
394        return Map.of();
395    }
396    
397    public Map<GroupIdentity, Map<UserOrGroup, Set<String>>> getProfilesForGroups(Set<GroupIdentity> groups)
398    {
399        return Map.of();
400    }
401    
402    public Map<UserIdentity, Map<UserOrGroup, Set<String>>> getProfilesForUsers(UserIdentity user)
403    {
404        return Map.of();
405    }
406    
407    public boolean isInheritanceDisallowed()
408    {
409        return false;
410    }
411    
412    public ModelAwareDataHolder getTemplateParametersHolder() throws AmetysRepositoryException
413    {
414        return null;
415    }
416}