001/*
002 *  Copyright 2012 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.newsletter.userpref;
017
018import java.time.ZonedDateTime;
019import java.util.ArrayList;
020import java.util.Date;
021import java.util.HashMap;
022import java.util.HashSet;
023import java.util.List;
024import java.util.Map;
025import java.util.Set;
026import java.util.UUID;
027
028import org.apache.avalon.framework.component.Component;
029import org.apache.avalon.framework.logger.AbstractLogEnabled;
030import org.apache.avalon.framework.service.ServiceException;
031import org.apache.avalon.framework.service.ServiceManager;
032import org.apache.avalon.framework.service.Serviceable;
033
034import org.ametys.core.user.User;
035import org.ametys.core.user.UserIdentity;
036import org.ametys.core.user.UserManager;
037import org.ametys.core.userpref.UserPreferencesException;
038import org.ametys.core.userpref.UserPreferencesStorage;
039import org.ametys.plugins.newsletter.category.CategoryProviderExtensionPoint;
040import org.ametys.plugins.newsletter.daos.Subscriber;
041import org.ametys.plugins.newsletter.daos.SubscribersDAO;
042import org.ametys.web.userpref.FOUserPreferencesConstants;
043
044/**
045 * Retrieves and stores newsletter user preferences values as subscriptions.
046 */
047public class NewsletterUserPreferencesStorage extends AbstractLogEnabled implements UserPreferencesStorage, Component, Serviceable
048{
049    
050    /** The front-office users manager. */
051    protected UserManager _foUserManager;
052    
053    /** The category provider extension point. */
054    protected CategoryProviderExtensionPoint _categoryEP;
055    
056    /** The subscribers DAO. */
057    protected SubscribersDAO _subscribersDao;
058    
059    @Override
060    public void service(ServiceManager serviceManager) throws ServiceException
061    {
062        _foUserManager = (UserManager) serviceManager.lookup(UserManager.ROLE);
063        _categoryEP = (CategoryProviderExtensionPoint) serviceManager.lookup(CategoryProviderExtensionPoint.ROLE);
064        _subscribersDao = (SubscribersDAO) serviceManager.lookup(SubscribersDAO.ROLE);
065    }
066    
067    @Override
068    public Map<String, String> getUnTypedUserPrefs(UserIdentity userIdentity, String storageContext, Map<String, String> contextVars) throws UserPreferencesException
069    {
070        try
071        {
072            Map<String, String> preferenceValues = new HashMap<>();
073            
074            User user = _foUserManager.getUser(userIdentity.getPopulationId(), userIdentity.getLogin());
075            String siteName = contextVars.get(FOUserPreferencesConstants.CONTEXT_VAR_SITENAME);
076            
077            if (user != null && siteName != null)
078            {
079                List<Subscriber> subscriptions = _subscribersDao.getSubscriptions(user.getEmail(), siteName);
080                for (Subscriber subscription : subscriptions)
081                {
082                    preferenceValues.put(subscription.getCategoryId(), "true");
083                }
084            }
085            
086            return preferenceValues;
087        }
088        catch (Exception e)
089        {
090            String message = "Error getting newsletter user preferences for login " + userIdentity + " and context " + storageContext;
091            getLogger().error(message, e);
092            throw new UserPreferencesException(message, e);
093        }
094    }
095    
096    @Override
097    public void setUserPreferences(UserIdentity userIdentity, String storageContext, Map<String, String> contextVars, Map<String, String> preferences) throws UserPreferencesException
098    {
099        try
100        {
101            User user = _foUserManager.getUser(userIdentity.getPopulationId(), userIdentity.getLogin());
102            String siteName = contextVars.get(FOUserPreferencesConstants.CONTEXT_VAR_SITENAME);
103            
104            if (user != null && siteName != null)
105            {
106                List<Subscriber> newSubscribers = new ArrayList<>();
107                Set<String> removeTokens = new HashSet<>();
108                
109                Map<String, String> existingCategoryIds = getExistingCategoryIds(user.getEmail(), siteName);
110                
111                for (String categoryId : preferences.keySet())
112                {
113                    String value = preferences.get(categoryId);
114                    
115                    if (value.equals("true") && _categoryEP.hasCategory(categoryId) && !existingCategoryIds.containsKey(categoryId))
116                    {
117                        Subscriber subscriber = getSubscription(siteName, user, categoryId);
118                        newSubscribers.add(subscriber);
119                    }
120                    else if (!value.equals("true") && _categoryEP.hasCategory(categoryId) && existingCategoryIds.containsKey(categoryId))
121                    {
122                        String token = existingCategoryIds.get(categoryId);
123                        removeTokens.add(token);
124                    }
125                }
126                
127                // Modify the subscriptions.
128                _subscribersDao.modifySubscriptions(newSubscribers, removeTokens);
129            }
130        }
131        catch (Exception e)
132        {
133            String message = "Error setting newsletter user preferences for login " + userIdentity + " and context " + storageContext;
134            getLogger().error(message, e);
135            throw new UserPreferencesException(message, e);
136        }
137    }
138    
139    @Override
140    public void removeUserPreferences(UserIdentity userIdentity, String storageContext, Map<String, String> contextVars) throws UserPreferencesException
141    {
142        try
143        {
144            User user = _foUserManager.getUser(userIdentity.getPopulationId(), userIdentity.getLogin());
145            String siteName = contextVars.get(FOUserPreferencesConstants.CONTEXT_VAR_SITENAME);
146            
147            if (user != null && siteName != null)
148            {
149                // Remove the subscriptions.
150                _subscribersDao.unsubscribe(user.getEmail(), storageContext);
151            }
152        }
153        catch (Exception e)
154        {
155            String message = "Error removing newsletter subscriptions for login " + userIdentity + " and context " + storageContext;
156            getLogger().error(message, e);
157            throw new UserPreferencesException(message, e);
158        }
159    }
160    
161    @Override
162    public String getUserPreferenceAsString(UserIdentity userIdentity, String storageContext, Map<String, String> contextVars, String id) throws UserPreferencesException
163    {
164        String value = null;
165        
166        Boolean booleanValue = getUserPreferenceAsBoolean(userIdentity, storageContext, contextVars, id);
167        
168        if (booleanValue != null)
169        {
170            value = booleanValue.toString();
171        }
172        
173        return value;
174    }
175    
176    @Override
177    public Long getUserPreferenceAsLong(UserIdentity userIdentity, String storageContext, Map<String, String> contextVars, String id) throws UserPreferencesException
178    {
179        return null;
180    }
181    
182    @Override
183    public ZonedDateTime getUserPreferenceAsDate(UserIdentity userIdentity, String storageContext, Map<String, String> contextVars, String id) throws UserPreferencesException
184    {
185        return null;
186    }
187    
188    @Override
189    public Boolean getUserPreferenceAsBoolean(UserIdentity userIdentity, String storageContext, Map<String, String> contextVars, String id) throws UserPreferencesException
190    {
191        try
192        {
193            Boolean value = null;
194            
195            User user = _foUserManager.getUser(userIdentity.getPopulationId(), userIdentity.getLogin());
196            String siteName = contextVars.get(FOUserPreferencesConstants.CONTEXT_VAR_SITENAME);
197            
198            if (user != null && siteName != null)
199            {
200                Subscriber subscriber = _subscribersDao.getSubscriber(user.getEmail(), siteName, id);
201                
202                value = Boolean.valueOf(subscriber != null);
203            }
204            
205            return value;
206        }
207        catch (Exception e)
208        {
209            throw new UserPreferencesException("Error getting newsletter user preferences for login " + userIdentity + " and context " + storageContext, e);
210        }
211    }
212    
213    @Override
214    public Double getUserPreferenceAsDouble(UserIdentity userIdentity, String storageContext, Map<String, String> contextVars, String id) throws UserPreferencesException
215    {
216        return null;
217    }
218    
219    /**
220     * Create a subscriber object from the given input. 
221     * @param siteName the site name.
222     * @param user the user.
223     * @param categoryId the category ID.
224     * @return the Subscriber object.
225     */
226    protected Subscriber getSubscription(String siteName, User user, String categoryId)
227    {
228        return getSubscription(siteName, user, categoryId, true);
229    }
230    
231    /**
232     * Create a subscriber object from the given input. 
233     * @param siteName the site name.
234     * @param user the user.
235     * @param categoryId the category ID.
236     * @param generateDateAndToken true to generate a token and set the subscription date, false otherwise.
237     * @return the Subscriber object.
238     */
239    protected Subscriber getSubscription(String siteName, User user, String categoryId, boolean generateDateAndToken)
240    {
241        Subscriber subscriber = new Subscriber();
242        subscriber.setEmail(user.getEmail());
243        subscriber.setSiteName(siteName);
244        subscriber.setCategoryId(categoryId);
245        
246        if (generateDateAndToken)
247        {
248            subscriber.setSubscribedAt(new Date());
249            
250            // Generate unique token.
251            String token = UUID.randomUUID().toString();
252            subscriber.setToken(token);
253        }
254        
255        return subscriber;
256    }
257    
258    /**
259     * Get the existing subscriptions for a user in a given site.
260     * @param email the user e-mail address.
261     * @param siteName the site name.
262     * @return a Set of category IDs, to which user has subscribed.
263     */
264    protected Map<String, String> getExistingCategoryIds(String email, String siteName)
265    {
266        Map<String, String> existingCategoryIds = new HashMap<>();
267        
268        List<Subscriber> existingSubscriptions = _subscribersDao.getSubscriptions(email, siteName);
269        for (Subscriber subscription : existingSubscriptions)
270        {
271            existingCategoryIds.put(subscription.getCategoryId(), subscription.getToken());
272        }
273        
274        return existingCategoryIds;
275    }
276}