001/* 002 * Copyright 2024 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.odfweb.rights; 017 018import org.apache.avalon.framework.context.Context; 019import org.apache.avalon.framework.context.ContextException; 020import org.apache.avalon.framework.context.Contextualizable; 021import org.apache.avalon.framework.service.ServiceException; 022import org.apache.avalon.framework.service.ServiceManager; 023import org.apache.cocoon.components.ContextHelper; 024import org.apache.cocoon.environment.Request; 025import org.apache.commons.lang3.StringUtils; 026 027import org.ametys.cms.repository.Content; 028import org.ametys.core.cache.Cache; 029import org.ametys.core.user.UserIdentity; 030import org.ametys.odf.ODFHelper; 031import org.ametys.odf.ProgramItem; 032import org.ametys.odf.program.AbstractProgram; 033import org.ametys.odf.program.Container; 034import org.ametys.plugins.core.impl.cache.AbstractCacheKey; 035import org.ametys.plugins.odfweb.repository.OdfPageHandler; 036import org.ametys.plugins.odfweb.repository.OdfPageResolver; 037import org.ametys.plugins.repository.AmetysObjectIterable; 038import org.ametys.runtime.config.Config; 039import org.ametys.runtime.i18n.I18nizableText; 040import org.ametys.web.WebHelper; 041import org.ametys.web.repository.site.Site; 042import org.ametys.web.repository.site.SiteManager; 043 044/** 045 * Implementation of {@link ODFRoleAccessControllerHelper} that consider current site to get program items with user as role. 046 * 047 */ 048public class ODFRoleAccessControllerHelper extends org.ametys.odf.rights.ODFRoleAccessControllerHelper implements Contextualizable 049{ 050 private static final String __CACHE_BY_SITE_ID = ODFRoleAccessControllerHelper.class.getName() + "$cacheBySite"; 051 052 private SiteManager _siteManager; 053 private OdfPageHandler _odfPageHandler; 054 private OdfPageResolver _odfPageResolver; 055 private ODFHelper _odfHelper; 056 057 private Context _context; 058 059 public void contextualize(Context context) throws ContextException 060 { 061 _context = context; 062 } 063 064 @Override 065 public void service(ServiceManager smanager) throws ServiceException 066 { 067 super.service(smanager); 068 _siteManager = (SiteManager) smanager.lookup(SiteManager.ROLE); 069 _odfPageHandler = (OdfPageHandler) smanager.lookup(OdfPageHandler.ROLE); 070 _odfPageResolver = (OdfPageResolver) smanager.lookup(OdfPageResolver.ROLE); 071 _odfHelper = (ODFHelper) smanager.lookup(ODFHelper.ROLE); 072 } 073 074 @Override 075 public void initialize() throws Exception 076 { 077 if (!_cacheManager.hasCache(__CACHE_BY_SITE_ID)) 078 { 079 _cacheManager.createRequestCache(__CACHE_BY_SITE_ID, 080 new I18nizableText("plugin.odf-web", "PLUGINS_ODF_WEB_CACHE_ROLE_ACCESS_CONTROLLER_LABEL"), 081 new I18nizableText("plugin.odf-web", "PLUGINS_ODF_WEB_CACHE_ROLE_ACCESS_CONTROLLER_DESCRIPTION"), 082 false 083 ); 084 } 085 } 086 087 static class CacheKey extends AbstractCacheKey 088 { 089 CacheKey(UserIdentity userIdentity, String siteName, String roleAttributePath) 090 { 091 super(userIdentity, siteName, roleAttributePath); 092 } 093 094 static CacheKey of(UserIdentity userIdentity, String siteName, String roleAttributePath) 095 { 096 return new CacheKey(userIdentity, siteName, roleAttributePath); 097 } 098 099 } 100 101 @Override 102 public boolean hasODFRoleOnAnyContent(UserIdentity user, String attributePath) 103 { 104 Cache<CacheKey, Boolean> cache = _getCacheBySite(); 105 106 Request request = ContextHelper.getRequest(_context); 107 String siteName = WebHelper.getSiteName(request); 108 109 CacheKey key = CacheKey.of(user, siteName, attributePath); 110 return cache.get(key, __ -> _hasODFRoleOnAnyProgramItem(user, siteName, attributePath)); 111 } 112 113 private boolean _hasODFRoleOnAnyProgramItem(UserIdentity user, String siteName, String attributePath) 114 { 115 AmetysObjectIterable<Content> contents = _odfRightHelper.getContentsWithUserAsRole(user, attributePath); 116 if (contents.getSize() == 0) 117 { 118 // user has no ODF role on program items 119 return false; 120 } 121 122 if (StringUtils.isNotBlank(siteName)) 123 { 124 Site site = _siteManager.getSite(siteName); 125 126 String odfMainSite = Config.getInstance().getValue("odf.web.site.name"); 127 if (siteName.equals(odfMainSite)) 128 { 129 // Allow access to main ODF site for user with a ODF role 130 return true; 131 } 132 else if (_odfPageHandler.hasOdfRootPage(site)) 133 { 134 // Check if at least one program item is part of ODF sitemap tree of current site (taking into account ODF restrictions) 135 for (Content content : contents) 136 { 137 if (content instanceof Container container) 138 { 139 for (AbstractProgram abstractProgram : _odfHelper.getParentAbstractPrograms(container)) 140 { 141 if (!_odfPageResolver.getReferencingPages(abstractProgram, siteName, null).isEmpty()) 142 { 143 return true; 144 } 145 } 146 } 147 else if (content instanceof ProgramItem programItem && !_odfPageResolver.getReferencingPages(programItem, siteName, null).isEmpty()) 148 { 149 return true; 150 } 151 } 152 153 // No find program item which is part of ODF tree on current site (there is no ODF root page, or ODF restrictions do not match program items) 154 return false; 155 } 156 else 157 { 158 // User has ONLY access to main ODF site 159 return false; 160 } 161 } 162 else 163 { 164 // user has ODF role on program items on no site context 165 return true; 166 } 167 } 168 169 private Cache<CacheKey, Boolean> _getCacheBySite() 170 { 171 return _cacheManager.get(__CACHE_BY_SITE_ID); 172 } 173}