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}