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}