001/* 002 * Copyright 2020 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.accesscontroller; 017 018import java.util.ArrayList; 019import java.util.Collection; 020import java.util.HashMap; 021import java.util.List; 022import java.util.Map; 023import java.util.Set; 024 025import org.apache.avalon.framework.service.ServiceException; 026import org.apache.avalon.framework.service.ServiceManager; 027import org.apache.avalon.framework.service.Serviceable; 028import org.apache.cocoon.components.ContextHelper; 029import org.apache.commons.collections.MapUtils; 030 031import org.ametys.cms.contenttype.ContentTypesHelper; 032import org.ametys.cms.repository.Content; 033import org.ametys.cms.repository.ContentQueryHelper; 034import org.ametys.cms.repository.DefaultContent; 035import org.ametys.cms.repository.MixinTypeExpression; 036import org.ametys.core.group.GroupIdentity; 037import org.ametys.core.right.AccessController; 038import org.ametys.core.right.AccessExplanation; 039import org.ametys.core.right.RightsException; 040import org.ametys.core.user.UserIdentity; 041import org.ametys.plugins.core.impl.right.AbstractRightBasedAccessController; 042import org.ametys.plugins.repository.AmetysObjectIterable; 043import org.ametys.plugins.repository.AmetysObjectResolver; 044import org.ametys.plugins.repository.query.expression.AndExpression; 045import org.ametys.plugins.repository.query.expression.Expression; 046import org.ametys.plugins.repository.query.expression.Expression.Operator; 047import org.ametys.plugins.repository.query.expression.ExpressionContext; 048import org.ametys.plugins.repository.query.expression.StringExpression; 049import org.ametys.plugins.repository.query.expression.UserExpression; 050import org.ametys.plugins.ugc.UGCConstants; 051import org.ametys.plugins.ugc.page.UGCPage; 052import org.ametys.plugins.ugc.page.UGCPageHandler; 053import org.ametys.runtime.i18n.I18nizableText; 054import org.ametys.web.WebHelper; 055import org.ametys.web.repository.SiteAwareAmetysObject; 056import org.ametys.web.repository.page.Page; 057import org.ametys.web.repository.site.Site; 058import org.ametys.web.repository.site.SiteManager; 059import org.ametys.web.repository.sitemap.Sitemap; 060import org.ametys.web.rights.PageAccessController; 061 062/** 063 * {@link AccessController} so creator of a UGC content types receive edit/delete rights on it 064 * 065 */ 066public class UGCCreatorPageAccessController extends AbstractRightBasedAccessController implements Serviceable 067{ 068 private static final List<String> __CREATOR_RIGHTS = List.of("Front_Edition_Access_Right"); 069 070 /** ContentTypes Helper */ 071 protected ContentTypesHelper _cTypeHelper; 072 /** The ametys object resolver */ 073 protected AmetysObjectResolver _resolver; 074 /** The site manager */ 075 protected SiteManager _siteManager; 076 /** the UGC page handler */ 077 protected UGCPageHandler _ugcPageHandler; 078 079 public void service(ServiceManager smanager) throws ServiceException 080 { 081 _cTypeHelper = (ContentTypesHelper) smanager.lookup(ContentTypesHelper.ROLE); 082 _resolver = (AmetysObjectResolver) smanager.lookup(AmetysObjectResolver.ROLE); 083 _siteManager = (SiteManager) smanager.lookup(SiteManager.ROLE); 084 _ugcPageHandler = (UGCPageHandler) smanager.lookup(UGCPageHandler.ROLE); 085 } 086 087 public boolean supports(Object object) 088 { 089 return object instanceof UGCPage; 090 } 091 092 public AccessResult getPermission(UserIdentity user, Set<GroupIdentity> userGroups, String rightId, Object object) 093 { 094 if (((UGCPage) object).getContent().getCreator().equals(user)) 095 { 096 return __CREATOR_RIGHTS.contains(rightId) ? AccessResult.USER_ALLOWED : AccessResult.UNKNOWN; 097 } 098 099 return AccessResult.UNKNOWN; 100 } 101 102 public AccessResult getReadAccessPermission(UserIdentity user, Set<GroupIdentity> userGroups, Object object) 103 { 104 return AccessResult.UNKNOWN; 105 } 106 107 /** 108 * If creator, access to a list of rights 109 */ 110 public Map<String, AccessResult> getPermissionByRight(UserIdentity user, Set<GroupIdentity> userGroups, Object object) 111 { 112 Map<String, AccessResult> permissionByRight = new HashMap<>(); 113 114 if (((UGCPage) object).getContent().getCreator().equals(user)) 115 { 116 for (String rightId : __CREATOR_RIGHTS) 117 { 118 permissionByRight.put(rightId, AccessResult.USER_ALLOWED); 119 } 120 } 121 122 return permissionByRight; 123 } 124 125 public AccessResult getPermissionForAnonymous(String rightId, Object object) 126 { 127 return AccessResult.UNKNOWN; 128 } 129 130 public AccessResult getReadAccessPermissionForAnonymous(Object object) 131 { 132 return AccessResult.UNKNOWN; 133 } 134 135 public AccessResult getPermissionForAnyConnectedUser(String rightId, Object object) 136 { 137 return AccessResult.UNKNOWN; 138 } 139 140 public AccessResult getReadAccessPermissionForAnyConnectedUser(Object object) 141 { 142 return AccessResult.UNKNOWN; 143 } 144 145 /** 146 * If right requested is in the list, the creator is added the list of USER_ALLOWED 147 */ 148 public Map<UserIdentity, AccessResult> getPermissionByUser(String rightId, Object object) 149 { 150 Map<UserIdentity, AccessResult> permissionByUser = new HashMap<>(); 151 152 if (__CREATOR_RIGHTS.contains(rightId)) 153 { 154 permissionByUser.put(((UGCPage) object).getContent().getCreator(), AccessResult.USER_ALLOWED); 155 } 156 return permissionByUser; 157 } 158 159 public Map<UserIdentity, AccessResult> getReadAccessPermissionByUser(Object object) 160 { 161 return MapUtils.EMPTY_MAP; 162 } 163 164 public Map<GroupIdentity, AccessResult> getPermissionByGroup(String rightId, Object object) 165 { 166 return MapUtils.EMPTY_MAP; 167 } 168 169 public Map<GroupIdentity, AccessResult> getReadAccessPermissionByGroup(Object object) 170 { 171 return MapUtils.EMPTY_MAP; 172 } 173 174 public boolean hasUserAnyPermissionOnWorkspace(Set<Object> workspacesContexts, UserIdentity user, Set<GroupIdentity> userGroups, String rightId) 175 { 176 return false; 177 } 178 179 public boolean hasUserAnyReadAccessPermissionOnWorkspace(Set<Object> workspacesContexts, UserIdentity user, Set<GroupIdentity> userGroups) 180 { 181 return false; 182 } 183 184 public boolean hasAnonymousAnyPermissionOnWorkspace(Set<Object> workspacesContexts, String rightId) 185 { 186 return false; 187 } 188 189 public boolean hasAnonymousAnyReadAccessPermissionOnWorkspace(Set<Object> workspacesContexts) 190 { 191 return false; 192 } 193 194 public boolean hasAnyConnectedUserAnyPermissionOnWorkspace(Set<Object> workspacesContexts, String rightId) 195 { 196 return false; 197 } 198 199 public boolean hasAnyConnectedUserAnyReadAccessPermissionOnWorkspace(Set<Object> workspacesContexts) 200 { 201 return false; 202 } 203 204 @Override 205 protected AccessExplanation _getAccessExplanation(AccessResult result, Object object, UserIdentity user, Set<GroupIdentity> groups, String rightId) 206 { 207 switch (result) 208 { 209 case USER_ALLOWED: 210 case UNKNOWN: 211 return new AccessExplanation( 212 getId(), 213 result, 214 new I18nizableText("plugin.ugc", "PLUGINS_UGC_CREATOR_ACCESS_CONTROLLER_" + result.name() + "_EXPLANATION", 215 Map.of("title", new I18nizableText(((UGCPage) object).getTitle())) 216 ) 217 ); 218 default: 219 return AccessController.getDefaultAccessExplanation(getId(), result); 220 } 221 } 222 223 public I18nizableText getObjectLabel(Object object) 224 { 225 if (object instanceof Page page) 226 { 227 return new I18nizableText(PageAccessController.getPageObjectLabel(page)); 228 } 229 throw new RightsException("Unsupported context: " + object.toString()); 230 } 231 232 public I18nizableText getObjectCategory(Object object) 233 { 234 return PageAccessController.PAGE_CONTEXT_CATEGORY; 235 } 236 237 @Override 238 protected Iterable< ? extends Object> getHandledObjects(UserIdentity identity, Set<GroupIdentity> groups, Set<Object> workspacesContexts) 239 { 240 241 String siteName = WebHelper.getSiteName(ContextHelper.getRequest(_context)); 242 Site site = _siteManager.getSite(siteName); 243 244 if (site != null) 245 { 246 List<Page> pages = new ArrayList<>(); 247 248 Expression typeExpr = new MixinTypeExpression(Operator.EQ, UGCConstants.UGC_MIXIN_TYPE); 249 250 ExpressionContext expressionContextForInternal = ExpressionContext.newInstance().withInternal(true); 251 Expression userExpression = new UserExpression(DefaultContent.METADATA_CREATOR, Operator.EQ, identity, expressionContextForInternal); 252 Expression siteExpression = new StringExpression(SiteAwareAmetysObject.METADATA_SITE, Operator.EQ, siteName, expressionContextForInternal); 253 254 String query = ContentQueryHelper.getContentXPathQuery(new AndExpression(siteExpression, typeExpr, userExpression)); 255 try (AmetysObjectIterable<Content> contents = _resolver.query(query)) 256 { 257 for (Content content : contents) 258 { 259 try (AmetysObjectIterable<Sitemap> sitemaps = site.getSitemaps()) 260 { 261 for (Sitemap sitemap: sitemaps) 262 { 263 for (String type : content.getTypes()) 264 { 265 _ugcPageHandler.getUgcPage(content, siteName, sitemap.getSitemapName(), type) 266 .ifPresent(page -> pages.add(page)); 267 } 268 } 269 } 270 } 271 } 272 273 } 274 return List.of(); 275 } 276 277 @Override 278 protected Collection<String> getHandledRights() 279 { 280 return __CREATOR_RIGHTS; 281 } 282}