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.Collection; 019import java.util.HashMap; 020import java.util.List; 021import java.util.Map; 022import java.util.Set; 023 024import org.apache.avalon.framework.service.ServiceException; 025import org.apache.avalon.framework.service.ServiceManager; 026import org.apache.avalon.framework.service.Serviceable; 027import org.apache.cocoon.components.ContextHelper; 028import org.apache.commons.collections.MapUtils; 029import org.apache.commons.lang3.StringUtils; 030 031import org.ametys.cms.contenttype.ContentTypesHelper; 032import org.ametys.cms.repository.Content; 033import org.ametys.cms.repository.ContentQueryHelper; 034import org.ametys.cms.repository.ContentTypeOrMixinExpression; 035import org.ametys.cms.repository.DefaultContent; 036import org.ametys.cms.rights.ContentAccessController; 037import org.ametys.core.group.GroupIdentity; 038import org.ametys.core.right.AccessController; 039import org.ametys.core.right.AccessExplanation; 040import org.ametys.core.right.RightsException; 041import org.ametys.core.user.UserIdentity; 042import org.ametys.plugins.core.impl.right.AbstractRightBasedAccessController; 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.runtime.i18n.I18nizableText; 051import org.ametys.web.WebHelper; 052import org.ametys.web.repository.SiteAwareAmetysObject; 053 054/** 055 * {@link AccessController} so creator of a UGC content types receive edit/delete rights on it 056 * 057 */ 058public class UGCCreatorContentAccessController extends AbstractRightBasedAccessController implements Serviceable 059{ 060 private static final List<String> __CREATOR_RIGHTS = List.of( 061 "Front_Edition_Access_Right", 062 "Workflow_Rights_Edition_Online", 063 "CMS_Rights_DeleteContent", 064 "Workflow_Rights_Validate" 065 ); 066 067 /** ContentTypes Helper */ 068 protected ContentTypesHelper _cTypeHelper; 069 /** The ametys object resolver */ 070 protected AmetysObjectResolver _resolver; 071 072 public void service(ServiceManager smanager) throws ServiceException 073 { 074 _cTypeHelper = (ContentTypesHelper) smanager.lookup(ContentTypesHelper.ROLE); 075 _resolver = (AmetysObjectResolver) smanager.lookup(AmetysObjectResolver.ROLE); 076 } 077 078 public boolean isSupported(Object object) 079 { 080 return object instanceof Content && _cTypeHelper.isInstanceOf((Content) object, UGCConstants.UGC_MIXIN_TYPE); 081 } 082 083 public AccessResult getPermission(UserIdentity user, Set<GroupIdentity> userGroups, String rightId, Object object) 084 { 085 if (object instanceof Content && ((Content) object).getCreator().equals(user)) 086 { 087 return __CREATOR_RIGHTS.contains(rightId) ? AccessResult.USER_ALLOWED : AccessResult.UNKNOWN; 088 } 089 090 return AccessResult.UNKNOWN; 091 } 092 093 public AccessResult getReadAccessPermission(UserIdentity user, Set<GroupIdentity> userGroups, Object object) 094 { 095 return AccessResult.UNKNOWN; 096 } 097 098 /** 099 * If creator, access to a list of rights 100 */ 101 public Map<String, AccessResult> getPermissionByRight(UserIdentity user, Set<GroupIdentity> userGroups, Object object) 102 { 103 Map<String, AccessResult> permissionByRight = new HashMap<>(); 104 105 if (((Content) object).getCreator().equals(user)) 106 { 107 for (String rightId : __CREATOR_RIGHTS) 108 { 109 permissionByRight.put(rightId, AccessResult.USER_ALLOWED); 110 } 111 } 112 113 return permissionByRight; 114 } 115 116 public AccessResult getPermissionForAnonymous(String rightId, Object object) 117 { 118 return AccessResult.UNKNOWN; 119 } 120 121 public AccessResult getReadAccessPermissionForAnonymous(Object object) 122 { 123 return AccessResult.UNKNOWN; 124 } 125 126 public AccessResult getPermissionForAnyConnectedUser(String rightId, Object object) 127 { 128 return AccessResult.UNKNOWN; 129 } 130 131 public AccessResult getReadAccessPermissionForAnyConnectedUser(Object object) 132 { 133 return AccessResult.UNKNOWN; 134 } 135 136 /** 137 * If right requested is in the list, the creator is added the list of USER_ALLOWED 138 */ 139 public Map<UserIdentity, AccessResult> getPermissionByUser(String rightId, Object object) 140 { 141 Map<UserIdentity, AccessResult> permissionByUser = new HashMap<>(); 142 143 if (__CREATOR_RIGHTS.contains(rightId)) 144 { 145 permissionByUser.put(((Content) object).getCreator(), AccessResult.USER_ALLOWED); 146 } 147 return permissionByUser; 148 } 149 150 public Map<UserIdentity, AccessResult> getReadAccessPermissionByUser(Object object) 151 { 152 return MapUtils.EMPTY_MAP; 153 } 154 155 public Map<GroupIdentity, AccessResult> getPermissionByGroup(String rightId, Object object) 156 { 157 return MapUtils.EMPTY_MAP; 158 } 159 160 public Map<GroupIdentity, AccessResult> getReadAccessPermissionByGroup(Object object) 161 { 162 return MapUtils.EMPTY_MAP; 163 } 164 165 public boolean hasUserAnyPermissionOnWorkspace(Set<Object> workspacesContexts, UserIdentity user, Set<GroupIdentity> userGroups, String rightId) 166 { 167 return false; 168 } 169 170 public boolean hasUserAnyReadAccessPermissionOnWorkspace(Set<Object> workspacesContexts, UserIdentity user, Set<GroupIdentity> userGroups) 171 { 172 return false; 173 } 174 175 public boolean hasAnonymousAnyPermissionOnWorkspace(Set<Object> workspacesContexts, String rightId) 176 { 177 return false; 178 } 179 180 public boolean hasAnonymousAnyReadAccessPermissionOnWorkspace(Set<Object> workspacesContexts) 181 { 182 return false; 183 } 184 185 public boolean hasAnyConnectedUserAnyPermissionOnWorkspace(Set<Object> workspacesContexts, String rightId) 186 { 187 return false; 188 } 189 190 public boolean hasAnyConnectedUserAnyReadAccessPermissionOnWorkspace(Set<Object> workspacesContexts) 191 { 192 return false; 193 } 194 195 @Override 196 public AccessExplanation getStandardAccessExplanation(AccessResult permission, Object object) 197 { 198 switch (permission) 199 { 200 case USER_ALLOWED: 201 case UNKNOWN: 202 return new AccessExplanation( 203 getId(), 204 permission, 205 new I18nizableText("plugin.ugc", "PLUGINS_UGC_CREATOR_ACCESS_CONTROLLER_" + permission.name() + "_EXPLANATION", 206 Map.of("title", new I18nizableText(((Content) object).getTitle())) 207 ) 208 ); 209 default: 210 return super.getStandardAccessExplanation(permission, object); 211 } 212 } 213 214 public I18nizableText getObjectLabel(Object object) 215 { 216 if (object instanceof Content content) 217 { 218 return new I18nizableText(content.getTitle()); 219 } 220 throw new RightsException("Unsupported context: " + object.toString()); 221 } 222 223 public I18nizableText getObjectCategory(Object object) 224 { 225 return ContentAccessController.CONTENT_CONTEXT_CATEGORY; 226 } 227 228 @Override 229 protected Iterable< ? extends Object> getHandledObjects(UserIdentity identity, Set<GroupIdentity> groups) 230 { 231 String siteName = WebHelper.getSiteName(ContextHelper.getRequest(_context)); 232 233 if (StringUtils.isNotBlank(siteName)) 234 { 235 Expression typeExpr = new ContentTypeOrMixinExpression(Operator.EQ, UGCConstants.UGC_MIXIN_TYPE); 236 Expression userExpression = new UserExpression(DefaultContent.METADATA_CREATOR, Operator.EQ, identity); 237 Expression siteExpression = new StringExpression(SiteAwareAmetysObject.METADATA_SITE, Operator.EQ, siteName); 238 String query = ContentQueryHelper.getContentXPathQuery(new AndExpression(typeExpr, userExpression, siteExpression)); 239 return _resolver.query(query); 240 } 241 return List.of(); 242 } 243 244 @Override 245 protected Collection<String> getHandledRights(UserIdentity identity, Set<GroupIdentity> groups, Object object) 246 { 247 return __CREATOR_RIGHTS; 248 } 249}