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.core.userpref;
017
018import java.util.ArrayList;
019import java.util.Collections;
020import java.util.List;
021import java.util.Map;
022
023import org.apache.avalon.framework.service.ServiceException;
024import org.apache.avalon.framework.service.ServiceManager;
025import org.apache.avalon.framework.service.Serviceable;
026import org.apache.commons.lang.StringUtils;
027
028import org.ametys.core.user.User;
029import org.ametys.core.user.UserIdentity;
030import org.ametys.core.user.dataprovider.UserDataProvider;
031import org.ametys.core.util.JSONUtils;
032import org.ametys.plugins.core.ui.user.DefaultProfileImageProvider.ProfileImageSource;
033import org.ametys.plugins.core.ui.user.ProfileImageProvider;
034import org.ametys.plugins.core.ui.user.SetUserProfileAction;
035import org.ametys.runtime.plugin.component.AbstractLogEnabled;
036
037/**
038 * A user data provider which gets the value from the global user preferences associated with the {@link User} for context admin
039 */
040public class UserPreferencesDataProvider extends AbstractLogEnabled implements UserDataProvider, Serviceable
041{
042    /** The ID of this data provider */
043    public static final String USER_PREFERENCES_DATA_PROVIDER_ID = UserPreferencesDataProvider.class.getName();
044    
045    /** The supported elements */
046    protected static List<String> _supportedElements = new ArrayList<>(List.of(User.IMAGE_DATA_ID, "timezone", "language"));
047    
048    /** The user preferences extension point */
049    protected UserPreferencesExtensionPoint _userPrefEP;
050    /** The user preferences manager */
051    protected UserPreferencesManager _userPrefManager;
052    /** The Default profile image provider */
053    protected ProfileImageProvider _imageProvider;
054    /** The json utils */
055    protected JSONUtils _jsonUtils;
056    
057    public void service(ServiceManager manager) throws ServiceException
058    {
059        _userPrefEP = (UserPreferencesExtensionPoint) manager.lookup(UserPreferencesExtensionPoint.ROLE);
060        _userPrefManager = (UserPreferencesManager) manager.lookup(UserPreferencesManager.ROLE);
061        _imageProvider = (ProfileImageProvider) manager.lookup(ProfileImageProvider.ROLE);
062        _jsonUtils = (JSONUtils) manager.lookup(JSONUtils.ROLE);
063    }
064    
065    public int getPriority()
066    {
067        return 20000;
068    }
069    
070    public boolean supports(String element)
071    {
072        return _supportedElements.contains(element);
073    }
074    
075    public Object getValue(User user, String dataId)
076    {
077        try
078        {
079            if (User.IMAGE_DATA_ID.equals(dataId))
080            {
081                return _getUserPrefImageAccessor(user.getIdentity());
082            }
083            else
084            {
085                Map<String, String> userPref = _userPrefManager.getUnTypedUserPrefs(user.getIdentity(), StringUtils.EMPTY, Collections.EMPTY_MAP);
086                
087                if (userPref != null && userPref.get(dataId) != null && StringUtils.isNotBlank(userPref.get(dataId)))
088                {
089                    return userPref.get(dataId);
090                }
091            }
092        }
093        catch (UserPreferencesException e)
094        {
095            getLogger().warn("An error occurred while retrieving user preference of user {}", user.getIdentity(), e);
096        }
097        
098        return null;
099    }
100    
101    private UserPreferencesImageAccessor _getUserPrefImageAccessor(UserIdentity user)
102    {
103        Map<String, Object> userPrefImgData = _getRawUserPrefImage(user);
104        if (userPrefImgData != null)
105        {
106            String rawImageSource = (String) userPrefImgData.remove("source");
107            ProfileImageSource profileImageSource = getProfileImageSource(rawImageSource);
108            
109            if (profileImageSource == null)
110            {
111                return null;
112            }
113            
114            @SuppressWarnings("unchecked")
115            Map<String, Object> sourceParams = (Map<String, Object>) userPrefImgData.get("parameters");
116            
117            return new UserPreferencesImageAccessor(user, profileImageSource, sourceParams, _imageProvider);
118        }
119        
120        return null;
121    }
122    
123    /**
124     * Get the profile image user pref
125     * @param user The user
126     * @return The map stored in the user pref
127     */
128    private Map<String, Object> _getRawUserPrefImage(UserIdentity user)
129    {
130        try
131        {
132            String userPrefImgJson = _userPrefManager.getUserPreferenceAsString(user, StringUtils.EMPTY, Collections.EMPTY_MAP, SetUserProfileAction.USERPREF_PROFILE_IMAGE);
133            if (StringUtils.isNotEmpty(userPrefImgJson))
134            {
135                return _jsonUtils.convertJsonToMap(userPrefImgJson);
136            }
137        }
138        catch (Exception e)
139        {
140            getLogger().error(String.format("Unable to retrieve the '%s' userpref for user '%s'", SetUserProfileAction.USERPREF_PROFILE_IMAGE, user), e);
141        }
142        
143        return null;
144    }
145    
146    /**
147     * Get the profile image source given a source input string
148     * @param imageSourceStr The input string representing the source
149     * @return The profile image source.
150     */
151    public ProfileImageSource getProfileImageSource(String imageSourceStr)
152    {
153        ProfileImageSource profileImageSource = null;
154        
155        try
156        {
157            profileImageSource = ProfileImageSource.valueOf(imageSourceStr.toUpperCase());
158        }
159        catch (IllegalArgumentException | NullPointerException e)
160        {
161            // Do Nothing
162        }
163        
164        return profileImageSource;
165    }
166}