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