001/* 002 * Copyright 2015 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.subscribe; 017 018import java.util.Collection; 019import java.util.Collections; 020import java.util.Date; 021import java.util.HashMap; 022import java.util.LinkedHashSet; 023import java.util.List; 024import java.util.Map; 025import java.util.Set; 026import java.util.UUID; 027import java.util.regex.Pattern; 028 029import org.apache.avalon.framework.service.ServiceException; 030import org.apache.avalon.framework.service.ServiceManager; 031import org.apache.commons.lang.StringUtils; 032 033import org.ametys.core.ui.Callable; 034import org.ametys.core.ui.StaticClientSideElement; 035import org.ametys.core.util.mail.SendMailHelper; 036import org.ametys.plugins.newsletter.category.Category; 037import org.ametys.plugins.newsletter.category.CategoryProviderExtensionPoint; 038import org.ametys.plugins.newsletter.daos.Subscriber; 039import org.ametys.plugins.newsletter.daos.SubscribersDAO; 040import org.ametys.plugins.newsletter.daos.SubscribersDAO.UnsubscribeOrigin; 041 042/** 043 * Client side element for newsletter subscribers 044 */ 045public class SubscribersClientSideElement extends StaticClientSideElement 046{ 047 private static final Pattern __EMAIL_VALIDATOR = SendMailHelper.EMAIL_VALIDATION; 048 049 /** The subscribers DAO. */ 050 protected SubscribersDAO _subscribersDao; 051 052 /** The category provider extension point. */ 053 protected CategoryProviderExtensionPoint _categoryProviderEP; 054 055 @Override 056 public void service(ServiceManager smanager) throws ServiceException 057 { 058 super.service(smanager); 059 _subscribersDao = (SubscribersDAO) smanager.lookup(SubscribersDAO.ROLE); 060 _categoryProviderEP = (CategoryProviderExtensionPoint) smanager.lookup(CategoryProviderExtensionPoint.ROLE); 061 } 062 063 /** 064 * Add a list of subscribers to the newsletter category of the specified site 065 * @param siteName The site name 066 * @param categoryId The category id 067 * @param emailsList The list of emails. Emails can be separeted by a new line or a semicolon. 068 * @return The result, with the count of subscribed or error emails. 069 */ 070 @Callable(rights = "Plugins_Newsletter_Right_HandleSubscribers") 071 public Map<String, Object> addSubscribers (String siteName, String categoryId, String emailsList) 072 { 073 Map<String, Object> result = new HashMap<>(); 074 075 // Test if the category exists. 076 Category category = _categoryProviderEP.getCategory(categoryId); 077 if (category == null) 078 { 079 return Collections.singletonMap("error", "unknown-category"); 080 } 081 082 // Extract the emails from the import file. 083 Collection<String> emails = getEmails(emailsList); 084 085 if (!emails.isEmpty()) 086 { 087 // Insert the emails. 088 insertSubscribers(emails, categoryId, siteName, result); 089 } 090 else 091 { 092 result.put("subscribedCount", "0"); 093 result.put("existingCount", "0"); 094 result.put("errorCount", "0"); 095 } 096 097 result.put("success", "true"); 098 result.put("categoryId", categoryId); 099 100 return result; 101 } 102 103 /** 104 * Extract the emails from the field. 105 * @param emailsList the list of emails 106 * @return a collection of the emails. 107 */ 108 protected Collection<String> getEmails(String emailsList) 109 { 110 Set<String> emails = new LinkedHashSet<>(); 111 112 String[] part = emailsList.split("[;\n]"); 113 for (String line : part) 114 { 115 String email = StringUtils.trimToEmpty(line); 116 if (__EMAIL_VALIDATOR.matcher(email.toLowerCase()).matches() && StringUtils.isNotBlank(email)) 117 { 118 emails.add(email); 119 } 120 else 121 { 122 getLogger().warn("Import subscribers email: '" + email + "' is not a valid email; it will be ignored"); 123 } 124 } 125 126 return emails; 127 } 128 129 130 /** 131 * Insert subscribers 132 * @param emails the list of emails 133 * @param categoryId the id of the newsletter category 134 * @param siteName the name of the sites 135 * @param result the result map 136 */ 137 protected void insertSubscribers(Collection<String> emails, String categoryId, String siteName, Map<String, Object> result) 138 { 139 int subscribedCount = 0; 140 int existingCount = 0; 141 int errorCount = 0; 142 143 for (String email : emails) 144 { 145 if (_subscribersDao.getSubscriber(email, siteName, categoryId) == null) 146 { 147 Subscriber subscriber = new Subscriber(); 148 subscriber.setEmail(email); 149 subscriber.setSiteName(siteName); 150 subscriber.setCategoryId(categoryId); 151 subscriber.setSubscribedAt(new Date()); 152 153 // Generate unique token. 154 String token = UUID.randomUUID().toString(); 155 subscriber.setToken(token); 156 157 _subscribersDao.subscribe(subscriber); 158 159 if (getLogger().isInfoEnabled()) 160 { 161 getLogger().info("The user with email '" + email + "' subscribed to the newsletter with the token " + token); 162 } 163 164 subscribedCount++; 165 } 166 else 167 { 168 existingCount++; 169 } 170 } 171 172 result.put("subscribedCount", Integer.toString(subscribedCount)); 173 result.put("existingCount", Integer.toString(existingCount)); 174 result.put("errorCount", Integer.toString(errorCount)); 175 } 176 177 178 /** 179 * Remove a list of subscribers from the newsletter category of the specified site 180 * @param siteName The site name 181 * @param categoryId The category id 182 * @param emails The list of emails. 183 * @return The error message, or an empty map if everything is ok. 184 */ 185 @Callable(rights = "Plugins_Newsletter_Right_HandleSubscribers") 186 public Map<String, Object> removeSubscribers (String siteName, String categoryId, List<String> emails) 187 { 188 Map<String, Object> result = new HashMap<>(); 189 190 // Test if the category exists. 191 Category category = _categoryProviderEP.getCategory(categoryId); 192 if (category == null) 193 { 194 return Collections.singletonMap("message", "unknown-category"); 195 } 196 197 if (emails.size() > 0) 198 { 199 for (String email : emails) 200 { 201 Subscriber subscriber = _subscribersDao.getSubscriber(email, siteName, categoryId); 202 203 if (subscriber != null) 204 { 205 String token = subscriber.getToken(); 206 207 _subscribersDao.unsubscribe(token, UnsubscribeOrigin.ADMINISTRATOR); 208 209 if (getLogger().isInfoEnabled()) 210 { 211 getLogger().info("The user with email '" + email + "' unsubscribed from the newsletter in category " + categoryId + " of site " + siteName); 212 } 213 } 214 else 215 { 216 getLogger().error("Impossible to find and remove from the newsletter the subscriber with email '" + email + "' in category " + categoryId + " of site " + siteName); 217 } 218 } 219 } 220 221 return result; 222 } 223}