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