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.userdirectory.userdataprovider; 017 018import java.util.ArrayList; 019import java.util.Collection; 020import java.util.Collections; 021import java.util.Comparator; 022import java.util.HashSet; 023import java.util.List; 024import java.util.Map; 025import java.util.Set; 026import java.util.stream.Collectors; 027 028import org.apache.avalon.framework.activity.Initializable; 029import org.apache.avalon.framework.context.Context; 030import org.apache.avalon.framework.context.ContextException; 031import org.apache.avalon.framework.context.Contextualizable; 032import org.apache.avalon.framework.service.ServiceException; 033import org.apache.avalon.framework.service.ServiceManager; 034import org.apache.avalon.framework.service.Serviceable; 035import org.apache.cocoon.components.ContextHelper; 036import org.apache.cocoon.environment.Request; 037 038import org.ametys.cms.contenttype.ContentTypesHelper; 039import org.ametys.cms.data.File; 040import org.ametys.cms.repository.Content; 041import org.ametys.core.user.User; 042import org.ametys.core.user.dataprovider.UserDataProvider; 043import org.ametys.plugins.userdirectory.UserDirectoryHelper; 044import org.ametys.runtime.model.ModelItem; 045import org.ametys.runtime.plugin.component.AbstractLogEnabled; 046import org.ametys.web.WebHelper; 047 048/** 049 * A {@link UserDataProvider} that finds data from the ContentUser associated to the User or UserIdentity given 050 */ 051public class ContentUserDataProvider extends AbstractLogEnabled implements UserDataProvider, Serviceable, Initializable, Contextualizable 052{ 053 private static final Comparator<Content> __COMPARATOR = Comparator.comparing(Content::getName); 054 private Set<String> _supportedData; 055 private UserDirectoryHelper _userDirectoryHelper; 056 private ContentTypesHelper _contentTypesHelper; 057 private Context _context; 058 059 public void service(ServiceManager manager) throws ServiceException 060 { 061 _userDirectoryHelper = (UserDirectoryHelper) manager.lookup(UserDirectoryHelper.ROLE); 062 _contentTypesHelper = (ContentTypesHelper) manager.lookup(ContentTypesHelper.ROLE); 063 } 064 065 public void contextualize(Context context) throws ContextException 066 { 067 _context = context; 068 } 069 070 public int getPriority() 071 { 072 return 10000; 073 } 074 075 public void initialize() throws Exception 076 { 077 _supportedData = new HashSet<>(); 078 079 // Get the content types of a ud user 080 Map<String, Object> contentTypesList = _contentTypesHelper.getContentTypesList(Collections.singletonList("org.ametys.plugins.userdirectory.Content.user"), 081 true /* inherited */, 082 false /* checkRights */, 083 true /* includePrivate */, 084 false /* includeMixins */, 085 false /* includeAbstract*/); 086 087 @SuppressWarnings("unchecked") 088 List<Map<String, Object>> contentTypes = (List<Map<String, Object>>) contentTypesList.get("contentTypes"); 089 090 // Get the model items names of all the model items that can be in a ud user 091 for (Map<String, Object> contentType : contentTypes) 092 { 093 Collection< ? extends ModelItem> modelItems = _contentTypesHelper.getModelItems(List.of(contentType.get("id")) 094 .toArray(String[]::new)); 095 096 _supportedData.addAll(modelItems.stream() 097 .map(ModelItem::getName) 098 .collect(Collectors.toSet())); 099 } 100 } 101 102 public boolean supports(String element) 103 { 104 // Check if the element requested can be supported. Can return true but not have a value for a specific user. 105 return _supportedData.contains(element); 106 } 107 108 @Override 109 public boolean hasValue(User user, String dataId) 110 { 111 // Sort users by name in order to always retrieve the same value by dataId 112 List<Content> contentUsers = _getSortedContentUsers(user); 113 114 // Get the ud users and check if it has a value for the data requested 115 for (Content contentUser : contentUsers) 116 { 117 if (hasValue(contentUser, dataId)) 118 { 119 return true; 120 } 121 } 122 123 return false; 124 } 125 126 private boolean hasValue(Content contentUser , String dataId) 127 { 128 return contentUser != null && contentUser.hasValue(dataId); 129 } 130 131 public Object getValue(User user, String dataId) 132 { 133 // Sort users by name in order to always retrieve the same value by dataId 134 List<Content> contentUsers = _getSortedContentUsers(user); 135 136 // Get the ud users and retrieve the value wanted if it exists 137 for (Content contentUser : contentUsers) 138 { 139 if (hasValue(contentUser, dataId)) 140 { 141 Object value = contentUser.getValue(dataId); 142 143 if (User.IMAGE_DATA_ID.equals(dataId) && value != null && value instanceof File file) 144 { 145 return new UserDirectoryImageAccessor(file, getLogger()); 146 } 147 else 148 { 149 return value; 150 } 151 } 152 } 153 154 return null; 155 } 156 157 private List<Content> _getSortedContentUsers(User user) 158 { 159 Request request = ContextHelper.getRequest(_context); 160 String lang = WebHelper.findLanguage(request); 161 162 List<Content> userContents = new ArrayList<>(_userDirectoryHelper.getUserContents(user.getIdentity(), lang)); 163 userContents.sort(__COMPARATOR); 164 return userContents; 165 } 166}