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}