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