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            // TODO NEWATTRIBUTEAPI_CONTENT: There is no attribute category on newsletter content. See how to deal with this metadata
089            String categoryID = content.getMetadataHolder().getString("category");
090            String siteName = content.getSiteName();
091            Site site = content.getSite();
092
093            boolean descending = site.getValue("newsletter-subscription-descending", false, false);
094            boolean ascending = site.getValue("newsletter-subscription-ascending", false, false);
095            
096            // TODO NEWATTRIBUTEAPI_CONTENT: There is no attribute category on newsletter content. See how to deal with this metadata
097            List<Subscriber> subscribers = _subscribersDAO.getSubscribers(content.getSiteName(), content.getMetadataHolder().getString("category"));
098            if (descending)
099            {
100                subscribers.addAll(_getSubscribersOfParentCategories(categoryID, siteName));
101            }
102            if (ascending)
103            {
104                subscribers.addAll(_getSubscribersOfChildCategories(categoryID, siteName));
105            }
106
107            Map<String, String> recipients = new HashMap<>();
108            for (Subscriber subcriber : subscribers)
109            {
110                recipients.put(subcriber.getEmail(), subcriber.getToken());
111            }            
112
113            _newsletterDAO.sendNewsletter(content, recipients);
114            
115            // TODO NEWATTRIBUTEAPI_CONTENT: There is no attribute sent on newsletter content. See how to deal with this metadata
116            content.getMetadataHolder().setMetadata("sent", true);
117            try
118            {
119                _newsletterDAO.removeTestNewsletter(content, site);
120            }
121            catch (RepositoryException e)
122            {
123                _logger.warn("Unable to remove the temporary test newsletter.", e);
124            }
125            content.saveChanges();
126            
127            // Send a google analytics event for every newsletter e-mail sent.
128            SendGAEventsEngine sendGaEngine = new SendGAEventsEngine();
129            sendGaEngine.initialize(_manager, _context);
130            sendGaEngine.parametrize(siteName, content, _newsletterDAO.getCategory(categoryID), recipients.size());
131            
132            new Thread(sendGaEngine).start();
133        }
134        catch (IOException e)
135        {
136            throw new WorkflowException("Unable to send mails !", e);
137        }
138        catch (ContextException e)
139        {
140            _logger.warn("Context exception when initializing an engine.", e);
141        }
142        catch (ServiceException e)
143        {
144            _logger.warn("Service exception when initializing an engine.", e);
145        }
146        
147    }
148    
149    /**
150     * Get the subscribers of parent categories
151     * @param categoryID The category id
152     * @param siteName The site name
153     * @return the subscribers of parent categories
154     */
155    protected List<Subscriber> _getSubscribersOfParentCategories (String categoryID, String siteName)
156    {
157        List<Subscriber> subscribers = new ArrayList<>();
158        
159        Category category = _newsletterDAO.getCategory(categoryID);
160        Category parentCategory = _newsletterDAO.getCategory(category.getParentId());
161        while (parentCategory != null)
162        {
163            subscribers.addAll(_subscribersDAO.getSubscribers(siteName, parentCategory.getId()));
164            parentCategory = _newsletterDAO.getCategory(parentCategory.getParentId());
165        }
166        
167        return subscribers;
168    }
169    
170    /**
171     * Get the subscribers of child categories
172     * @param categoryID The category id
173     * @param siteName The site name
174     * @return The subscribers of child categories
175     */
176    protected List<Subscriber> _getSubscribersOfChildCategories (String categoryID, String siteName)
177    {
178        List<Subscriber> subscribers = new ArrayList<>();
179        
180        CategoryProvider provider = _getProvider(categoryID);
181        
182        List<Category> children = provider.getCategories(categoryID);
183        for (Category child : children)
184        {
185            subscribers.addAll(_subscribersDAO.getSubscribers(siteName, child.getId()));
186            subscribers.addAll(_getSubscribersOfChildCategories (child.getId(), siteName));
187        }
188        
189        return subscribers;
190    }
191
192    /**
193     * Retrieve the request from which this component is called.
194     * @return the request
195     */
196    protected Request _getRequest()
197    {
198        return ContextHelper.getRequest(_context);
199    }
200    
201    /**
202     * Get the category provider
203     * @param categoryID The category id
204     * @return The category
205     */
206    protected CategoryProvider _getProvider (String categoryID)
207    {
208        Set<String> ids = _categoryProviderEP.getExtensionsIds();
209        for (String id : ids)
210        {
211            CategoryProvider provider = _categoryProviderEP.getExtension(id);
212            if (provider.hasCategory(categoryID))
213            {
214                return provider;
215            }
216        }
217        
218        return null;
219    }
220
221}