001/* 002 * Copyright 2014 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.cms.tag; 017 018import java.io.IOException; 019import java.util.ArrayList; 020import java.util.HashMap; 021import java.util.HashSet; 022import java.util.List; 023import java.util.Map; 024import java.util.Set; 025 026import javax.jcr.RepositoryException; 027 028import org.apache.avalon.framework.parameters.Parameters; 029import org.apache.avalon.framework.service.ServiceException; 030import org.apache.avalon.framework.service.ServiceManager; 031import org.apache.cocoon.ProcessingException; 032import org.apache.cocoon.acting.ServiceableAction; 033import org.apache.cocoon.environment.ObjectModelHelper; 034import org.apache.cocoon.environment.Redirector; 035import org.apache.cocoon.environment.Request; 036import org.apache.cocoon.environment.SourceResolver; 037import org.apache.commons.lang.StringUtils; 038import org.xml.sax.SAXException; 039 040import org.ametys.cms.repository.Content; 041import org.ametys.cms.tag.Tag.TagVisibility; 042import org.ametys.cms.tag.jcr.JCRTagProvider; 043import org.ametys.core.cocoon.JSonReader; 044import org.ametys.core.right.RightManager; 045import org.ametys.core.right.RightManager.RightResult; 046import org.ametys.core.user.CurrentUserProvider; 047import org.ametys.core.user.UserIdentity; 048import org.ametys.plugins.repository.AmetysObject; 049import org.ametys.plugins.repository.AmetysObjectResolver; 050import org.ametys.plugins.repository.AmetysRepositoryException; 051 052/** 053 * SAX events for tags 054 * 055 */ 056public class GetTagsAction extends ServiceableAction 057{ 058 /** The tag provider extension point */ 059 protected TagProviderExtensionPoint _tagProviderExtPt; 060 061 /** The Ametys object resolver */ 062 protected AmetysObjectResolver _resolver; 063 064 /** The rights manager. */ 065 protected RightManager _rightManager; 066 067 /** The current user provider. */ 068 protected CurrentUserProvider _currentUserProvider; 069 070 071 @Override 072 public void service(ServiceManager serviceManager) throws ServiceException 073 { 074 super.service(serviceManager); 075 _tagProviderExtPt = (TagProviderExtensionPoint) serviceManager.lookup(TagProviderExtensionPoint.ROLE); 076 _resolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE); 077 _rightManager = (RightManager) serviceManager.lookup(RightManager.ROLE); 078 _currentUserProvider = (CurrentUserProvider) serviceManager.lookup(CurrentUserProvider.ROLE); 079 080 } 081 082 @Override 083 public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws IOException, SAXException, ProcessingException 084 { 085 @SuppressWarnings("unchecked") 086 Map<String, Object> jsParameters = (Map<String, Object>) objectModel.get(ObjectModelHelper.PARENT_CONTEXT); 087 088 String parentId = (String) jsParameters.get("node"); 089 String nodeName = (String) jsParameters.get("nodeName"); 090 boolean onlyCustomTags = (Boolean) jsParameters.get("onlyCustomTags"); 091 092 @SuppressWarnings("unchecked") 093 List<String> objectTargetIds = (List<String>) jsParameters.get("objectTargetIds"); 094 095 String targetType = (String) jsParameters.get("targetType"); 096 097 @SuppressWarnings("unchecked") 098 Map<String, Object> contextualParameters = (Map<String, Object>) jsParameters.get("contextualParameters"); 099 100 List<Map<String, Object>> tags = new ArrayList<>(); 101 102 if (StringUtils.isEmpty(parentId) || parentId.equals("tag-root")) 103 { 104 Set<String> extensionsIds = getProvidersIds(onlyCustomTags); 105 106 for (String id : extensionsIds) 107 { 108 TagProvider tagProvider = _tagProviderExtPt.getExtension(id); 109 tags.add(providerToJSON(tagProvider, contextualParameters, targetType)); 110 } 111 } 112 else if (nodeName.startsWith("provider_")) 113 { 114 String providerId = nodeName.substring("provider_".length()); 115 TagProvider tagProvider = _tagProviderExtPt.getExtension(providerId); 116 117 if (tagProvider != null) 118 { 119 Map<String, Tag> childs = tagProvider.getFilteredTags(targetType, contextualParameters); 120 if (childs != null) 121 { 122 for (Tag tag : childs.values()) 123 { 124 tags.add(tagToJSON(tag, tagProvider, objectTargetIds)); 125 } 126 } 127 } 128 } 129 else 130 { 131 Set<String> extensionsIds = getProvidersIds(onlyCustomTags); 132 for (String id : extensionsIds) 133 { 134 TagProvider tagProvider = _tagProviderExtPt.getExtension(id); 135 if (tagProvider.hasTag(nodeName, contextualParameters)) 136 { 137 Tag parent = tagProvider.getTag(nodeName, contextualParameters); 138 Map<String, Tag> childs = parent.getTags(); 139 for (Tag tag : childs.values()) 140 { 141 if (targetType == null || tag.getTarget().getName().equals(targetType)) 142 { 143 tags.add(tagToJSON(tag, tagProvider, objectTargetIds)); 144 } 145 } 146 } 147 } 148 } 149 150 Map<String, Object> result = new HashMap<>(); 151 result.put("children", tags); 152 153 Request request = ObjectModelHelper.getRequest(objectModel); 154 request.setAttribute(JSonReader.OBJECT_TO_READ, result); 155 156 return EMPTY_MAP; 157 } 158 159 /** 160 * Get all providers IDs 161 * @param onlyCustomTags If true, return only JCR providers IDs. 162 * @return a set of providers IDs 163 */ 164 protected Set<String> getProvidersIds(boolean onlyCustomTags) 165 { 166 if (onlyCustomTags) 167 { 168 Set<String> extensionsIds = new HashSet<>(); 169 TagProvider tagProvider = _tagProviderExtPt.getExtension(JCRTagProvider.class.getName()); 170 extensionsIds.add(tagProvider.getId()); 171 return extensionsIds; 172 } 173 174 return _tagProviderExtPt.getExtensionsIds(); 175 } 176 177 /** 178 * Returns the tag providers' id 179 * @return The id of tag providers 180 */ 181 protected Set<String> getProvidersId() 182 { 183 return getProvidersIds(false); 184 } 185 186 /** 187 * Get tag's properties to JSON format 188 * @param tag The tag 189 * @param tagProvider the tag provider 190 * @param objectTargetIds the list of Ametys object ids. Can be empty 191 * @return The tag properties 192 */ 193 protected Map<String, Object> tagToJSON(Tag tag, TagProvider tagProvider, List<String> objectTargetIds) 194 { 195 Map<String, Object> infos = new HashMap<>(); 196 197 infos.put("id", tag.getId()); 198 infos.put("name", tag.getName()); 199 infos.put("title", tag.getTitle()); 200 infos.put("description", tag.getDescription()); 201 202 boolean authorized = isUserAuthorized(tag, objectTargetIds); 203 infos.put("authorized", authorized); 204 infos.put("creationAllowed", isCreationAllowed(tagProvider, tag)); 205 206 TagVisibility visibility = tag.getVisibility(); 207 infos.put("visibility", visibility.toString()); 208 209 TagTargetType tagTargetType = tag.getTarget(); 210 211 if (tagTargetType != null) 212 { 213 Map<String, Object> target2json = new HashMap<>(); 214 target2json.put("name", tagTargetType.getName()); 215 target2json.put("label", tagTargetType.getLabel()); 216 target2json.put("description", tagTargetType.getDescription()); 217 218 infos.put("target", target2json); 219 } 220 221 if (TagVisibility.PRIVATE.equals(visibility)) 222 { 223 if (authorized) 224 { 225 infos.put("iconSmall", "/plugins/cms/resources/img/tag/tag_private_16.png"); 226 infos.put("iconMedium", "/plugins/cms/resources/img/tag/tag_private_32.png"); 227 infos.put("iconLarge", "/plugins/cms/resources/img/tag/tag_private_50.png"); 228 } 229 else 230 { 231 infos.put("iconSmall", "/plugins/cms/resources/img/tag/tag_unauthorized_16.png"); 232 infos.put("iconMedium", "/plugins/cms/resources/img/tag/tag_unauthorized_32.png"); 233 infos.put("iconLarge", "/plugins/cms/resources/img/tag/tag_unauthorized_50.png"); 234 } 235 } 236 else 237 { 238 infos.put("iconSmall", "/plugins/cms/resources/img/tag/tag_16.png"); 239 infos.put("iconMedium", "/plugins/cms/resources/img/tag/tag_32.png"); 240 infos.put("iconLarge", "/plugins/cms/resources/img/tag/tag_50.png"); 241 } 242 243 if (tag.getTags().size() == 0) 244 { 245 infos.put("leaf", true); 246 } 247 248 249 return infos; 250 } 251 252 /** 253 * Get tag provider's properties to JSON format 254 * @param tagProvider the tag provider 255 * @param contextualParameters The contextual parameters 256 * @param targetType The type of target (such as 'content') 257 * @return The tag providers properties 258 * @throws AmetysRepositoryException If an error occurred 259 */ 260 protected Map<String, Object> providerToJSON(TagProvider tagProvider, Map<String, Object> contextualParameters, String targetType) 261 { 262 Map<String, Object> infos = new HashMap<>(); 263 264 if (tagProvider instanceof JCRTagProvider) 265 { 266 JCRTagProvider provider = (JCRTagProvider) tagProvider; 267 try 268 { 269 infos.put("id", provider.getRootNode(contextualParameters).getId()); 270 } 271 catch (AmetysRepositoryException e) 272 { 273 getLogger().error("Unable to get JCR tag provider root node", e); 274 } 275 catch (RepositoryException e) 276 { 277 getLogger().error("Unable to get JCR tag provider root node", e); 278 } 279 } 280 else 281 { 282 infos.put("id", tagProvider.getId()); 283 } 284 285 infos.put("type", "provider"); 286 infos.put("name", "provider_" + tagProvider.getId()); 287 infos.put("title", tagProvider.getLabel()); 288 infos.put("description", tagProvider.getDescription()); 289 infos.put("authorized", true); 290 infos.put("creationAllowed", isCreationAllowed(tagProvider, null)); 291 infos.put("iconSmall", "/plugins/cms/resources/img/tag/tags_16.png"); 292 infos.put("iconMedium", "/plugins/cms/resources/img/tag/tags_32.png"); 293 infos.put("iconLarge", "/plugins/cms/resources/img/tag/tags_50.png"); 294 295 if (tagProvider.getFilteredTags(targetType, contextualParameters).size() == 0) 296 { 297 infos.put("leaf", true); 298 } 299 return infos; 300 } 301 302 /** 303 * Test if a tag is visible to the current user. 304 * @param tag the Tag object. 305 * @param content the current content (can be null). 306 * @return true if the user has access to the tag, false otherwise. 307 */ 308 protected boolean isUserAuthorized(Tag tag, Content content) 309 { 310 if (content != null) 311 { 312 if (isPrivate(tag)) 313 { 314 return _rightManager.hasRight(_getCurrentUser(), "CMS_Rights_Content_Private_Tag", content) == RightResult.RIGHT_ALLOW; 315 } 316 else 317 { 318 return _rightManager.hasRight(_getCurrentUser(), "CMS_Rights_Content_Tag", content) == RightResult.RIGHT_ALLOW 319 || _rightManager.hasRight(_getCurrentUser(), "CMS_Rights_Content_Private_Tag", content) == RightResult.RIGHT_ALLOW; 320 } 321 } 322 323 return true; 324 } 325 326 /** 327 * Test if a tag is visible to the current user. 328 * @param tag the Tag object. 329 * @param objectTargetIds the ids of current Ametys objects 330 * @return true if the user has access to the tag, false otherwise. 331 */ 332 protected boolean isUserAuthorized(Tag tag, List<String> objectTargetIds) 333 { 334 if (objectTargetIds != null && objectTargetIds.size() > 0) 335 { 336 boolean hasRight = false; 337 for (String objectId : objectTargetIds) 338 { 339 AmetysObject ao = _resolver.resolveById(objectId); 340 341 if (ao instanceof Content && tag.getTarget().getName().equals("CONTENT")) 342 { 343 hasRight = isUserAuthorized (tag, (Content) ao) || hasRight; 344 } 345 } 346 return hasRight; 347 } 348 349 return true; 350 } 351 352 /** 353 * Determines if the current user can created tag 354 * @param tagProvider The tag provider 355 * @param tag The tag. Can be null. 356 * @return true if creation is allowed 357 */ 358 protected boolean isCreationAllowed(TagProvider tagProvider, Tag tag) 359 { 360 if (!(tagProvider instanceof JCRTagProvider)) 361 { 362 return false; 363 } 364 return _rightManager.hasRight(_getCurrentUser(), "CMS_Rights_Tags_HandleTag", "/cms") == RightResult.RIGHT_ALLOW; 365 } 366 367 /** 368 * Determines if a tag is private 369 * @param tag the tag to test 370 * @return true if a tag is private 371 */ 372 protected boolean isPrivate (Tag tag) 373 { 374 return tag.getVisibility() == TagVisibility.PRIVATE; 375 } 376 377 /** 378 * Provides the current user. 379 * @return the current user which cannot be <code>null</code>. 380 */ 381 protected UserIdentity _getCurrentUser() 382 { 383 return _currentUserProvider.getUser(); 384 } 385 386}