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.category;
017
018import java.util.ArrayList;
019import java.util.Arrays;
020import java.util.Collection;
021import java.util.List;
022
023import org.apache.avalon.framework.configuration.Configurable;
024import org.apache.avalon.framework.configuration.Configuration;
025import org.apache.avalon.framework.configuration.ConfigurationException;
026import org.apache.avalon.framework.logger.LogEnabled;
027import org.apache.avalon.framework.logger.Logger;
028import org.apache.avalon.framework.service.ServiceException;
029import org.apache.avalon.framework.service.ServiceManager;
030import org.apache.avalon.framework.service.Serviceable;
031
032import org.ametys.cms.repository.Content;
033import org.ametys.cms.repository.ContentTypeExpression;
034import org.ametys.plugins.repository.AmetysObjectIterable;
035import org.ametys.plugins.repository.AmetysObjectResolver;
036import org.ametys.plugins.repository.UnknownAmetysObjectException;
037import org.ametys.plugins.repository.query.expression.AndExpression;
038import org.ametys.plugins.repository.query.expression.Expression;
039import org.ametys.plugins.repository.query.expression.ExpressionContext;
040import org.ametys.plugins.repository.query.expression.Expression.Operator;
041import org.ametys.plugins.repository.query.expression.StringExpression;
042import org.ametys.runtime.i18n.I18nizableText;
043import org.ametys.runtime.plugin.component.PluginAware;
044import org.ametys.web.repository.page.ModifiablePage;
045import org.ametys.web.repository.page.Page;
046import org.ametys.web.repository.page.PageQueryHelper;
047import org.ametys.web.repository.page.jcr.DefaultPage;
048import org.ametys.web.tags.TagExpression;
049
050/**
051 * This class provides newsletter categories from the site map
052 *
053 */
054public class SitemapCategoryProvider implements LogEnabled, CategoryProvider, Serviceable, Configurable, PluginAware
055{
056    /** The root id */
057    public static final String TAG_NAME = "NEWSLETTER_CATEGORY";
058    /** The metadata name for newsletter template */
059    public static final String METADATA_TEMPLATE = "newsletterTemplate";
060    /** The metadata name for automatic newsletter ids. */
061    public static final String METADATA_AUTOMATIC_IDS = "newsletterAutomaticIds";
062    /** The metadata name for newsletter template */
063    public static final String CATEGORY_PREFIX_ID = "category_";
064    
065    /** The id */
066    protected String _id;
067    /** The label */
068    protected I18nizableText _label;
069    /** The description */
070    protected I18nizableText _description;
071    /** The plugin name */
072    protected String _pluginName;
073    /** The feature name */
074    protected String _featureName;
075
076    /** The Logger */
077    protected Logger _logger;
078    
079    private AmetysObjectResolver _resolver;
080
081    @Override
082    public void service(ServiceManager serviceManager) throws ServiceException
083    {
084        _resolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE);
085    }
086    
087    @Override
088    public void configure(Configuration configuration) throws ConfigurationException
089    {
090        _label = configureLabel(configuration);
091        _description = configureDescription(configuration);
092    }
093    
094    public void enableLogging(Logger logger)
095    {
096        _logger = logger;
097    }
098    
099    @Override
100    public boolean isWritable()
101    {
102        return false;
103    }
104    
105    @Override
106    public List<Category> getCategories(String siteName, String lang)
107    {
108        TagExpression expr = new TagExpression(Operator.EQ, TAG_NAME);
109        String xpathQuery = PageQueryHelper.getPageXPathQuery(siteName, lang, "", expr, null);
110        
111        List<Category> categories = new ArrayList<>();
112        
113        AmetysObjectIterable<DefaultPage> pages = _resolver.query(xpathQuery);
114        for (DefaultPage page : pages)
115        {
116            Category category = new Category(CATEGORY_PREFIX_ID + page.getId(), page.getName(), _id, new I18nizableText(page.getTitle()), null, page.getValue(METADATA_TEMPLATE), siteName, lang);
117            categories.add(category);
118        }
119        
120        return categories;
121    }
122    
123    @Override
124    public Collection<Category> getAllCategories(String siteName, String lang)
125    {
126        return getCategories(siteName, lang);
127    }
128    
129    @Override
130    public List<Category> getCategories(String categoryID)
131    {
132        return new ArrayList<>();
133    }
134
135    @Override
136    public boolean hasCategory(String categoryID)
137    {
138        if (categoryID.startsWith(CATEGORY_PREFIX_ID))
139        {
140            String pageID = categoryID.substring(CATEGORY_PREFIX_ID.length());
141            try
142            {
143                DefaultPage page = _resolver.resolveById(pageID);
144                if (page != null)
145                {
146                    return page.getTags().contains(TAG_NAME);
147                }
148            }
149            catch (UnknownAmetysObjectException e)
150            {
151                // Page does not exist anymore
152                return false;
153            }
154        }
155        return false;
156    }
157    
158    @Override
159    public Category getCategory(String categoryID)
160    {
161        if (categoryID.startsWith("category_"))
162        {
163            String pageID = categoryID.substring(CATEGORY_PREFIX_ID.length());
164            DefaultPage page = _resolver.resolveById(pageID);
165            if (page != null && page.getTags().contains(TAG_NAME))
166            {
167                return new Category(CATEGORY_PREFIX_ID + page.getId(), page.getName(), "provider_" + _id, new I18nizableText(page.getTitle()), new I18nizableText(""), page.getValue(METADATA_TEMPLATE), page.getSiteName(), page.getSitemapName());
168            }
169        }
170        return null;
171    }
172    
173    @Override
174    public void setTemplate(Category category, String templateName)
175    {
176        String categoryID = category.getId();
177        if (categoryID.startsWith("category_"))
178        {
179            String pageID = categoryID.substring(CATEGORY_PREFIX_ID.length());
180            ModifiablePage page = _resolver.resolveById(pageID);
181            if (page != null)
182            {
183                page.setValue(METADATA_TEMPLATE, templateName);
184                page.saveChanges();
185            }
186        }
187    }
188    
189    @Override
190    public Collection<String> getAutomaticIds(String categoryId)
191    {
192        if (categoryId.startsWith("category_"))
193        {
194            String pageID = categoryId.substring(CATEGORY_PREFIX_ID.length());
195            Page page = _resolver.resolveById(pageID);
196            if (page != null)
197            {
198                String[] autoIds = page.getValue(METADATA_AUTOMATIC_IDS, new String[0]);
199                
200                return Arrays.asList(autoIds);
201            }
202        }
203        
204        // Either the category ID is not a page category, or the page doesn't exist.
205        throw new IllegalArgumentException("The provided category ID is invalid.");
206    }
207    
208    @Override
209    public void setAutomatic(String categoryId, Collection<String> automaticNewsletterIds)
210    {
211        if (categoryId.startsWith("category_"))
212        {
213            String pageID = categoryId.substring(CATEGORY_PREFIX_ID.length());
214            Page page = _resolver.resolveById(pageID);
215            if (page != null && page instanceof ModifiablePage)
216            {
217                ModifiablePage modifiablePage = (ModifiablePage) page;
218                
219                // Convert to array.
220                String[] autoIdsArray = automaticNewsletterIds.toArray(new String[automaticNewsletterIds.size()]);
221                                
222                modifiablePage.setValue(METADATA_AUTOMATIC_IDS, autoIdsArray);
223                modifiablePage.saveChanges();
224                
225                return;
226            }
227        }
228        
229        // Either the category ID is not a page category, or the page doesn't exist.
230        throw new IllegalArgumentException("The provided category ID is invalid.");
231    }
232    
233    @Override
234    public AmetysObjectIterable<Content> getNewsletters(String categoryID, String siteName, String lang)
235    {
236        Expression cTypeExpr = new ContentTypeExpression(Operator.EQ, "org.ametys.plugins.newsletter.Content.newsletter");
237        Expression siteExpr = new StringExpression("site", Operator.EQ, siteName);
238        Expression catExpr = new StringExpression("category", Operator.EQ, categoryID, ExpressionContext.newInstance().withInternal(true));
239        Expression expr = new AndExpression(cTypeExpr, siteExpr, catExpr);
240        
241        String xpathQuery = org.ametys.plugins.repository.query.QueryHelper.getXPathQuery(null, "ametys:content", expr);
242        return _resolver.query(xpathQuery);
243    }
244    
245    @Override
246    public boolean hasChildren(String categoryID)
247    {
248        return false;
249    }
250
251    @Override
252    public boolean hasNewsletters(String categoryID, String siteName, String lang)
253    {
254        Expression expr = new ContentTypeExpression(Operator.EQ, "org.ametys.plugins.newsletter.Content.newsletter");
255        Expression siteExpr = new StringExpression("site", Operator.EQ, siteName);
256        expr = new AndExpression(expr, siteExpr);
257        Expression catExpr = new StringExpression("category", Operator.EQ, categoryID, ExpressionContext.newInstance().withInternal(true));
258        expr = new AndExpression(expr, catExpr);
259        
260        String xpathQuery = org.ametys.plugins.repository.query.QueryHelper.getXPathQuery(null, "ametys:content", expr);
261        
262        return _resolver.query(xpathQuery).iterator().hasNext();
263    }
264    
265    /**
266     * Configure label from the passed configuration
267     * @param configuration The configuration
268     * @return The label
269     * @throws ConfigurationException If an error occurred
270     */
271    protected I18nizableText configureLabel (Configuration configuration) throws ConfigurationException
272    {
273        Configuration labelConfiguration = configuration.getChild("label");
274        
275        if (labelConfiguration.getAttributeAsBoolean("i18n", false))
276        {
277            return new I18nizableText("plugin." + _pluginName, labelConfiguration.getValue(""));
278        }
279        else
280        {
281            return new I18nizableText(labelConfiguration.getValue(""));
282        }
283    }
284    
285    /**
286     * Configure description from the passed configuration
287     * @param configuration The configuration
288     * @return The description
289     * @throws ConfigurationException If an error occurred
290     */
291    protected I18nizableText configureDescription (Configuration configuration) throws ConfigurationException
292    {
293        Configuration descConfiguration = configuration.getChild("description");
294        
295        if (descConfiguration.getAttributeAsBoolean("i18n", false))
296        {
297            return new I18nizableText("plugin." + _pluginName, descConfiguration.getValue(""));
298        }
299        else
300        {
301            return new I18nizableText(descConfiguration.getValue(""));
302        }
303    }
304    
305    public void setPluginInfo(String pluginName, String featureName, String id)
306    {
307        _pluginName = pluginName;
308        _featureName = featureName;
309        _id = id;
310    }
311    
312    /**
313     * Get the plugin name
314     * @return the plugin name
315     */
316    public String getPluginName()
317    {
318        return _pluginName;
319    }
320
321    @Override
322    public I18nizableText getDescription()
323    {
324        return _description;
325    }
326
327    @Override
328    public String getId()
329    {
330        return _id;
331    }
332
333    @Override
334    public I18nizableText getLabel()
335    {
336        return _label;
337    }
338
339    @Override
340    public String getRootId(String siteName, String lang)
341    {
342        return _id;
343    }
344}