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