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.workflow;
017
018import java.io.IOException;
019import java.util.ArrayList;
020import java.util.HashMap;
021import java.util.List;
022import java.util.Map;
023import java.util.Set;
024
025import javax.jcr.RepositoryException;
026
027import org.apache.avalon.framework.context.Context;
028import org.apache.avalon.framework.context.ContextException;
029import org.apache.avalon.framework.context.Contextualizable;
030import org.apache.avalon.framework.service.ServiceException;
031import org.apache.avalon.framework.service.ServiceManager;
032import org.apache.cocoon.components.ContextHelper;
033import org.apache.cocoon.environment.Request;
034
035import org.ametys.cms.workflow.AbstractContentWorkflowComponent;
036import org.ametys.plugins.newsletter.NewsletterDAO;
037import org.ametys.plugins.newsletter.category.Category;
038import org.ametys.plugins.newsletter.category.CategoryProvider;
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.repository.content.jcr.DefaultWebContent;
043import org.ametys.web.repository.site.Site;
044
045import com.opensymphony.module.propertyset.PropertySet;
046import com.opensymphony.workflow.FunctionProvider;
047import com.opensymphony.workflow.WorkflowException;
048
049/**
050 * OSWorkflow function for creating a content.
051 */
052public class SendNewsletterFunction extends AbstractContentWorkflowComponent implements FunctionProvider, Contextualizable
053{
054    private SubscribersDAO _subscribersDAO;
055    private CategoryProviderExtensionPoint _categoryProviderEP;
056    
057    private Context _context;
058    private NewsletterDAO _newsletterDAO;
059    
060    @Override
061    public void service(ServiceManager manager) throws ServiceException
062    {
063        super.service(manager);
064        _subscribersDAO = (SubscribersDAO) manager.lookup(SubscribersDAO.ROLE);
065        _categoryProviderEP = (CategoryProviderExtensionPoint) manager.lookup(CategoryProviderExtensionPoint.ROLE);
066        _newsletterDAO = (NewsletterDAO) manager.lookup(NewsletterDAO.ROLE);
067    }
068
069    public void contextualize(Context context) throws ContextException
070    {
071        _context = context;
072    }
073    
074    @Override
075    public void execute(Map transientVars, Map args, PropertySet ps) throws WorkflowException
076    {
077        Request request = _getRequest();
078        if (request.getParameter("send") == null && request.getAttribute("send") == null)
079        {
080            // Do not send the newsletter
081            return;
082        }
083        
084        DefaultWebContent content = (DefaultWebContent) getContent(transientVars);
085        try
086        {
087            // Subscribers
088            String categoryID = content.getInternalDataHolder().getValue("category");
089            String siteName = content.getSiteName();
090            Site site = content.getSite();
091
092            boolean descending = site.getValue("newsletter-subscription-descending", false, false);
093            boolean ascending = site.getValue("newsletter-subscription-ascending", false, false);
094            
095            List<Subscriber> subscribers = _subscribersDAO.getSubscribers(content.getSiteName(), content.getInternalDataHolder().getValue("category"));
096            if (descending)
097            {
098                subscribers.addAll(_getSubscribersOfParentCategories(categoryID, siteName));
099            }
100            if (ascending)
101            {
102                subscribers.addAll(_getSubscribersOfChildCategories(categoryID, siteName));
103            }
104
105            Map<String, String> recipients = new HashMap<>();
106            for (Subscriber subcriber : subscribers)
107            {
108                recipients.put(subcriber.getEmail(), subcriber.getToken());
109            }            
110
111            _newsletterDAO.sendNewsletter(content, recipients);
112            
113            content.getInternalDataHolder().setValue("sent", true);
114            try
115            {
116                _newsletterDAO.removeTestNewsletter(content, site);
117            }
118            catch (RepositoryException e)
119            {
120                _logger.warn("Unable to remove the temporary test newsletter.", e);
121            }
122            content.saveChanges();
123            
124            // Send a google analytics event for every newsletter e-mail sent.
125            SendGAEventsEngine sendGaEngine = new SendGAEventsEngine();
126            sendGaEngine.initialize(_manager, _context);
127            sendGaEngine.parametrize(siteName, content, _newsletterDAO.getCategory(categoryID), recipients.size());
128            
129            new Thread(sendGaEngine).start();
130        }
131        catch (IOException e)
132        {
133            throw new WorkflowException("Unable to send mails !", e);
134        }
135        catch (ContextException e)
136        {
137            _logger.warn("Context exception when initializing an engine.", e);
138        }
139        catch (ServiceException e)
140        {
141            _logger.warn("Service exception when initializing an engine.", e);
142        }
143        
144    }
145    
146    /**
147     * Get the subscribers of parent categories
148     * @param categoryID The category id
149     * @param siteName The site name
150     * @return the subscribers of parent categories
151     */
152    protected List<Subscriber> _getSubscribersOfParentCategories (String categoryID, String siteName)
153    {
154        List<Subscriber> subscribers = new ArrayList<>();
155        
156        Category category = _newsletterDAO.getCategory(categoryID);
157        Category parentCategory = _newsletterDAO.getCategory(category.getParentId());
158        while (parentCategory != null)
159        {
160            subscribers.addAll(_subscribersDAO.getSubscribers(siteName, parentCategory.getId()));
161            parentCategory = _newsletterDAO.getCategory(parentCategory.getParentId());
162        }
163        
164        return subscribers;
165    }
166    
167    /**
168     * Get the subscribers of child categories
169     * @param categoryID The category id
170     * @param siteName The site name
171     * @return The subscribers of child categories
172     */
173    protected List<Subscriber> _getSubscribersOfChildCategories (String categoryID, String siteName)
174    {
175        List<Subscriber> subscribers = new ArrayList<>();
176        
177        CategoryProvider provider = _getProvider(categoryID);
178        
179        List<Category> children = provider.getCategories(categoryID);
180        for (Category child : children)
181        {
182            subscribers.addAll(_subscribersDAO.getSubscribers(siteName, child.getId()));
183            subscribers.addAll(_getSubscribersOfChildCategories (child.getId(), siteName));
184        }
185        
186        return subscribers;
187    }
188
189    /**
190     * Retrieve the request from which this component is called.
191     * @return the request
192     */
193    protected Request _getRequest()
194    {
195        return ContextHelper.getRequest(_context);
196    }
197    
198    /**
199     * Get the category provider
200     * @param categoryID The category id
201     * @return The category
202     */
203    protected CategoryProvider _getProvider (String categoryID)
204    {
205        Set<String> ids = _categoryProviderEP.getExtensionsIds();
206        for (String id : ids)
207        {
208            CategoryProvider provider = _categoryProviderEP.getExtension(id);
209            if (provider.hasCategory(categoryID))
210            {
211                return provider;
212            }
213        }
214        
215        return null;
216    }
217
218}