001/*
002 *  Copyright 2010 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.ArrayList;
019import java.util.Date;
020import java.util.HashMap;
021import java.util.List;
022import java.util.Map;
023import java.util.Set;
024import java.util.UUID;
025import java.util.regex.Matcher;
026import java.util.regex.Pattern;
027
028import org.apache.avalon.framework.parameters.Parameters;
029import org.apache.avalon.framework.service.ServiceException;
030import org.apache.avalon.framework.service.ServiceManager;
031import org.apache.cocoon.acting.ServiceableAction;
032import org.apache.cocoon.environment.ObjectModelHelper;
033import org.apache.cocoon.environment.Redirector;
034import org.apache.cocoon.environment.Request;
035import org.apache.cocoon.environment.SourceResolver;
036import org.apache.commons.lang.StringUtils;
037
038import org.ametys.plugins.newsletter.category.Category;
039import org.ametys.plugins.newsletter.category.CategoryProvider;
040import org.ametys.plugins.newsletter.category.CategoryProviderExtensionPoint;
041import org.ametys.plugins.newsletter.daos.Subscriber;
042import org.ametys.plugins.newsletter.daos.SubscribersDAO;
043import org.ametys.plugins.repository.AmetysObjectResolver;
044import org.ametys.core.captcha.CaptchaHelper;
045import org.ametys.web.cache.PageHelper;
046import org.ametys.web.repository.page.Page;
047import org.ametys.web.site.SiteConfigurationExtensionPoint;
048
049/**
050 * This action subscribes an email address to a newsletter
051 *
052 */
053public class SubscribeAction extends ServiceableAction
054{
055    /** The email pattern */
056    public static final Pattern EMAIL_PATTERN = Pattern.compile("^([a-zA-Z0-9]+(([\\.\\-\\_]?[a-zA-Z0-9]+)+)?)\\@(([a-zA-Z0-9]+[\\.\\-\\_])+[a-zA-Z0-9]{2,})$");
057    /** The subscribers DAO */
058    protected SubscribersDAO _subscribersDao;
059    /** The category providers manager */
060    protected CategoryProviderExtensionPoint _categoryProviderEP;
061    /** The site configuration */
062    protected SiteConfigurationExtensionPoint _siteConfiguration;
063    /** The Ametys object resolver */
064    protected AmetysObjectResolver _resolver;
065    /** Page helper */
066    protected PageHelper _pageHelper;
067    
068    @Override
069    public void service(ServiceManager smanager) throws ServiceException
070    {
071        super.service(smanager);
072        _subscribersDao = (SubscribersDAO) smanager.lookup(SubscribersDAO.ROLE);
073        _categoryProviderEP = (CategoryProviderExtensionPoint) smanager.lookup(CategoryProviderExtensionPoint.ROLE);
074        _siteConfiguration = (SiteConfigurationExtensionPoint) smanager.lookup(SiteConfigurationExtensionPoint.ROLE);
075        _resolver = (AmetysObjectResolver) smanager.lookup(AmetysObjectResolver.ROLE);
076        _pageHelper = (PageHelper) smanager.lookup(PageHelper.ROLE);
077    }
078    
079    @Override
080    public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws Exception
081    {
082        Map<String, String> result = new HashMap<>();
083        
084        Request request = ObjectModelHelper.getRequest(objectModel);
085        boolean subscribe = request.getParameter("subscribe") != null;
086        
087        String email = request.getParameter("email");
088        result.put("email", email);
089
090        if (subscribe)
091        {
092            try
093            {
094                String siteName = request.getParameter("siteName");
095                String[] categories = request.getParameterValues("category");
096                
097                // Validate email
098                if (!_validEmail(email))
099                {
100                    result.put("msg", "invalid-email");
101                    return result;
102                }
103                
104                Page page = _resolver.resolveById(request.getParameter("page-id"));
105                if (_pageHelper.isCaptchaRequired(page))
106                {
107                    String captchaKey = request.getParameter("captcha-key");
108                    String answer = request.getParameter("captcha");
109        
110                    // Validate captcha 
111                    if (!CaptchaHelper.checkAndInvalidate(captchaKey, answer))
112                    {
113                        result.put("msg", "invalid-captcha");
114                        return result;
115                    }
116                }
117                
118                // Validate categories
119                if (!_validCategory(categories))
120                {
121                    result.put("msg", "invalid-category");
122                    return result;
123                }
124                
125                
126                List<String> subscribeTo = new ArrayList<>();
127                List<String> alreadySubscribeTo = new ArrayList<>();
128                for (String categoryID : categories)
129                {
130                    if (_subscribersDao.getSubscriber(email, siteName, categoryID) == null)
131                    {
132                        Category category = _getCategory(categoryID);
133                        if (category != null)
134                        {
135                            Subscriber subscriber = new Subscriber();
136                            subscriber.setEmail(email);
137                            subscriber.setSiteName(siteName);
138                            subscriber.setCategoryId(categoryID);
139                            subscriber.setSubscribedAt(new Date());
140                            
141                            // Generate unique token
142                            String token = UUID.randomUUID().toString();
143                            subscriber.setToken(token);
144                            
145                            _subscribersDao.subscribe(subscriber);
146                            
147                            getLogger().info("The user with email '" + email + "' subscribed to the newsletter with the token " + token);
148                            
149                            subscribeTo.add(categoryID);
150                        }
151                    }
152                    else
153                    {
154                        alreadySubscribeTo.add(categoryID);
155                    }
156                }
157                
158                result.put("msg", "success");
159                String ids = "";
160                int i = 0;
161                for (String id : subscribeTo)
162                {
163                    if (i != 0)
164                    {
165                        ids += ",";
166                    }
167                    ids += id;
168                    i++;
169                }
170                result.put("subscribeTo", ids);
171                
172                ids = "";
173                i = 0;
174                for (String id : alreadySubscribeTo)
175                {
176                    if (i != 0)
177                    {
178                        ids += ",";
179                    }
180                    ids += id;
181                    i++;
182                }
183                result.put("alreadySubscribeTo", ids);
184            }
185            catch (Exception e)
186            {
187                result.put("msg", "failure");
188                getLogger().error("An error occurred during the subscription for the email '" + email + "'", e);
189            }
190        }
191        return result;
192    }
193    
194    /**
195     * Determines if the email address is valid
196     * @param email The email address
197     * @return true if the email is valid
198     */
199    protected boolean _validEmail (String email)
200    {
201        if (StringUtils.isEmpty(email))
202        {
203            return false;
204        }
205        
206        Matcher matcher = EMAIL_PATTERN.matcher(email);
207        return matcher.matches();
208    }
209    
210    /**
211     * Determines if the categories are valid
212     * @param categories The categories id
213     * @return true if the categories are valid
214     */
215    protected boolean _validCategory (String[] categories)
216    {
217        return categories != null && categories.length > 0;
218    }
219    
220
221    /**
222     * Get the category
223     * @param categoryID The category id
224     * @return the category
225     */
226    protected Category _getCategory (String categoryID)
227    {
228        Set<String> ids = _categoryProviderEP.getExtensionsIds();
229        for (String id : ids)
230        {
231            CategoryProvider provider = _categoryProviderEP.getExtension(id);
232            if (provider.hasCategory(categoryID))
233            {
234                return provider.getCategory(categoryID);
235            }
236        }
237        
238        return null;
239    }
240}