001/*
002 *  Copyright 2020 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.workspaces.news;
017
018import java.util.Set;
019
020import org.apache.commons.lang.IllegalClassException;
021import org.apache.commons.lang.StringUtils;
022
023import org.ametys.plugins.explorer.ExplorerNode;
024import org.ametys.plugins.explorer.resources.ModifiableResourceCollection;
025import org.ametys.plugins.explorer.resources.jcr.JCRResourcesCollectionFactory;
026import org.ametys.plugins.repository.AmetysRepositoryException;
027import org.ametys.plugins.repository.data.holder.ModifiableModelAwareDataHolder;
028import org.ametys.plugins.workspaces.AbstractWorkspaceModule;
029import org.ametys.plugins.workspaces.ObservationConstants;
030import org.ametys.plugins.workspaces.WorkspacesConstants;
031import org.ametys.plugins.workspaces.project.objects.Project;
032import org.ametys.runtime.i18n.I18nizableText;
033import org.ametys.web.repository.page.ModifiablePage;
034import org.ametys.web.repository.page.ModifiableZone;
035import org.ametys.web.repository.page.ModifiableZoneItem;
036import org.ametys.web.repository.page.Page.PageType;
037import org.ametys.web.repository.page.ZoneItem.ZoneType;
038import org.ametys.web.repository.sitemap.Sitemap;
039
040/**
041 * Workspaces module for news
042 */
043public class NewsWorkspaceModule extends AbstractWorkspaceModule
044{
045    /** The id of calendar module */
046    public static final String NEWS_MODULE_ID = NewsWorkspaceModule.class.getName();
047    
048    /** The id of news service */
049    public static final String NEWS_SERVICE_ID = "org.ametys.web.service.SearchService";
050    
051    /** Name of news's template */
052    public static final String NEWS_PAGE_TEMPLATE = "news";
053    
054    /** Search service content types */
055    protected static final String[] SEARCH_SERVICE_CONTENT_TYPES = new String[] {WorkspacesConstants.PROJECT_NEWS_CONTENT_TYPE_ID};
056    
057    /** Search service returnables */
058    protected static final String[] SEARCH_SERVICE_RETURNABLES = new String[] {"org.ametys.web.frontoffice.search.metamodel.impl.ContentReturnable"};
059    
060    /** Search service sorts */
061    protected static final String[] SEARCH_SERVICE_SORTS = new String[] {"{\"name\":\"ContentReturnable$ContentSearchable$indexingField$org.ametys.plugins.workspaces.Content.abstractNews$start-date\",\"sort\":\"DESC\"}", "{\"name\":\"ContentReturnable$ContentSearchable$indexingField$org.ametys.plugins.workspaces.Content.abstractNews$end-date\",\"sort\":\"DESC\"}"};
062    
063    /** Search service contexts */
064    protected static final String[] SEARCH_SERVICE_CONTEXTS = new String[] {"{\"sites\":\"{\\\"context\\\":\\\"CURRENT_SITE\\\",\\\"sites\\\":[]}\",\"search-sitemap-context\":\"{\\\"context\\\":\\\"CURRENT_SITE\\\",\\\"page\\\":null}\",\"context-lang\":\"CURRENT\",\"tags\":[]}"};
065    
066    /** Search service content view */
067    protected static final String SEARCH_SEARCH_CONTENT_VIEW = "portlet";
068    
069    /** Search service xslt */
070    protected static final String SEARCH_SERVICE_XSLT = "pages/services/search/project-news.xsl";
071    
072    /** Workspaces calendars node name */
073    private static final String __WORKSPACES_NEWS_NODE_NAME = "news";
074    
075    public String getId()
076    {
077        return NEWS_MODULE_ID;
078    }
079
080    public int getOrder()
081    {
082        return ORDER_NEWS;
083    }
084
085    public String getModuleName()
086    {
087        return __WORKSPACES_NEWS_NODE_NAME;
088    }
089
090    public Set<String> getAllowedEventTypes()
091    {
092        return Set.of(ObservationConstants.EVENT_PROJECT_NEWS_PUBLISHED);
093    }
094
095    public ModifiableResourceCollection getModuleRoot(Project project, boolean create)
096    {
097        try
098        {
099            ExplorerNode projectRootNode = project.getExplorerRootNode();
100            
101            if (projectRootNode instanceof ModifiableResourceCollection)
102            {
103                ModifiableResourceCollection projectRootNodeRc = (ModifiableResourceCollection) projectRootNode;
104                return _getAmetysObject(projectRootNodeRc, __WORKSPACES_NEWS_NODE_NAME, JCRResourcesCollectionFactory.RESOURCESCOLLECTION_NODETYPE, create);
105            }
106            else
107            {
108                throw new IllegalClassException(ModifiableResourceCollection.class, projectRootNode.getClass());
109            }
110        }
111        catch (AmetysRepositoryException e)
112        {
113            throw new AmetysRepositoryException("Error getting the news root node.", e);
114        }
115    }
116
117    @Override
118    protected String getModulePageName()
119    {
120        return "news";
121    }
122
123    public I18nizableText getModuleTitle()
124    {
125        return new I18nizableText("plugin." + _pluginName, "PLUGINS_WORKSPACES_PROJECT_MODULE_NEWS_LABEL");
126    }
127    public I18nizableText getModuleDescription()
128    {
129        return new I18nizableText("plugin." + _pluginName, "PLUGINS_WORKSPACES_PROJECT_MODULE_NEWS_DESCRIPTION");
130    }
131
132    @Override
133    protected I18nizableText getModulePageTitle()
134    {
135        return new I18nizableText("plugin." + _pluginName, "PLUGINS_WORKSPACES_PROJECT_WORKSPACE_PAGE_NEWS_TITLE");
136    }
137    
138    @Override
139    protected ModifiablePage _createModulePage(Project project, Sitemap sitemap, String name, I18nizableText pageTitle, String skinTemplate)
140    {
141        if (!sitemap.hasChild(name))
142        {
143            ModifiablePage page = sitemap.createChild(name, "ametys:defaultPage");
144            
145            // Title should not be missing, but just in case if the i18n message or the whole catalog does not exists in the requested language
146            // to prevent a non-user-friendly error and still generate the project workspace.
147            page.setTitle(StringUtils.defaultIfEmpty(_i18nUtils.translate(pageTitle, sitemap.getName()), "Missing title"));
148            page.setType(PageType.CONTAINER);
149            page.setTemplate(NEWS_PAGE_TEMPLATE);
150            page.setSiteName(sitemap.getSiteName());
151            page.setSitemapName(sitemap.getName());
152            
153            sitemap.saveChanges();
154            
155            return page;
156        }
157        else
158        {
159            return null;
160        }
161    }
162
163    @Override
164    protected void initializeModulePage(ModifiablePage modulePage)
165    {
166        modulePage.untag("SECTION");
167        
168        ModifiableZone defaultZone;
169        if (modulePage.hasZone("default"))
170        {
171            defaultZone = modulePage.getZone("default");
172        }
173        else
174        {
175            defaultZone = modulePage.createZone("default");            
176        }
177        
178        boolean hasService = defaultZone.getZoneItems().stream().anyMatch(zi -> NEWS_SERVICE_ID.equals(zi.getServiceId()));
179        
180        if (!hasService)
181        {
182            ModifiableZoneItem defaultZoneItem = defaultZone.addZoneItem();
183            defaultZoneItem.setType(ZoneType.SERVICE);
184            defaultZoneItem.setServiceId(NEWS_SERVICE_ID);
185            
186            ModifiableModelAwareDataHolder serviceDataHolder = defaultZoneItem.getServiceParameters();
187            serviceDataHolder.setValue("header", null);
188            serviceDataHolder.setValue("contentTypes", SEARCH_SERVICE_CONTENT_TYPES);
189            serviceDataHolder.setValue("returnables", SEARCH_SERVICE_RETURNABLES);
190            serviceDataHolder.setValue("initialSorts", SEARCH_SERVICE_SORTS);
191            serviceDataHolder.setValue("contexts", SEARCH_SERVICE_CONTEXTS);
192            serviceDataHolder.setValue("resultsPerPage", 12);
193            serviceDataHolder.setValue("rightCheckingMode", "exact");
194            serviceDataHolder.setValue("resultPlace", "ABOVE_CRITERIA");
195            serviceDataHolder.setValue("launchSearchAtStartup", true);
196            serviceDataHolder.setValue("rss", false);
197            serviceDataHolder.setValue("contentView", SEARCH_SEARCH_CONTENT_VIEW);
198            serviceDataHolder.setValue("xslt", SEARCH_SERVICE_XSLT);
199        }
200    }
201    
202    @Override
203    protected String getModulePageTemplate() 
204    {
205        return "page";
206    }
207
208}