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}