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