001/* 002 * Copyright 2025 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.odforientation; 017 018import java.io.IOException; 019import java.util.Arrays; 020import java.util.Collections; 021import java.util.List; 022import java.util.Locale; 023import java.util.Optional; 024 025import org.apache.avalon.framework.service.ServiceException; 026import org.apache.avalon.framework.service.ServiceManager; 027import org.apache.cocoon.ProcessingException; 028import org.apache.cocoon.environment.ObjectModelHelper; 029import org.apache.cocoon.environment.Request; 030import org.apache.cocoon.generation.ServiceableGenerator; 031import org.apache.cocoon.xml.AttributesImpl; 032import org.apache.cocoon.xml.XMLUtils; 033import org.apache.commons.lang3.LocaleUtils; 034import org.apache.commons.lang3.StringUtils; 035import org.xml.sax.SAXException; 036 037import org.ametys.cms.contenttype.ContentTypesHelper; 038import org.ametys.cms.repository.ContentTypeExpression; 039import org.ametys.cms.search.advanced.AbstractTreeNode; 040import org.ametys.cms.search.advanced.TreeLeaf; 041import org.ametys.core.util.LambdaUtils; 042import org.ametys.odf.orgunit.OrgUnit; 043import org.ametys.odf.orgunit.OrgUnitFactory; 044import org.ametys.odf.orgunit.RootOrgUnitProvider; 045import org.ametys.plugins.repository.AmetysObjectIterable; 046import org.ametys.plugins.repository.AmetysObjectResolver; 047import org.ametys.plugins.repository.query.QueryHelper; 048import org.ametys.plugins.repository.query.expression.Expression; 049import org.ametys.plugins.repository.query.expression.Expression.Operator; 050import org.ametys.runtime.model.View; 051import org.ametys.runtime.model.type.DataContext; 052import org.ametys.web.frontoffice.search.SearchService; 053import org.ametys.web.frontoffice.search.instance.SearchServiceInstance; 054import org.ametys.web.frontoffice.search.instance.SearchServiceInstanceManager; 055import org.ametys.web.repository.page.Page; 056import org.ametys.web.repository.page.Page.PageType; 057import org.ametys.web.repository.page.ZoneItem; 058import org.ametys.web.repository.page.ZoneItem.ZoneType; 059 060/** 061 * Generates the exhaustive list of orgunits 062 */ 063public class OrgUnitsGenerator extends ServiceableGenerator 064{ 065 private AmetysObjectResolver _resolver; 066 private RootOrgUnitProvider _rootOrgUnitProvider; 067 private ContentTypesHelper _cTypeHelper; 068 private SearchServiceInstanceManager _searchServiceInstanceManager; 069 070 @Override 071 public void service(ServiceManager serviceManager) throws ServiceException 072 { 073 super.service(serviceManager); 074 _resolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE); 075 _rootOrgUnitProvider = (RootOrgUnitProvider) serviceManager.lookup(RootOrgUnitProvider.ROLE); 076 _cTypeHelper = (ContentTypesHelper) serviceManager.lookup(ContentTypesHelper.ROLE); 077 _searchServiceInstanceManager = (SearchServiceInstanceManager) serviceManager.lookup(SearchServiceInstanceManager.ROLE); 078 } 079 080 @Override 081 public void generate() throws IOException, SAXException, ProcessingException 082 { 083 Request request = ObjectModelHelper.getRequest(objectModel); 084 085 String lang = parameters.getParameter("lang", (String) request.getAttribute("sitemapLanguage")); 086 Locale defaultLocale = LocaleUtils.toLocale(lang); 087 088 ZoneItem zoneItem = (ZoneItem) request.getAttribute(ZoneItem.class.getName()); 089 090 String contentView = zoneItem.getServiceParameters().getValue("contentView"); 091 View view = _cTypeHelper.getView(contentView, new String[] {OrgUnitFactory.ORGUNIT_CONTENT_TYPE}, new String[0]); 092 093 094 contentHandler.startDocument(); 095 096 XMLUtils.startElement(contentHandler, "orgunits"); 097 098 Expression expr = new ContentTypeExpression(Operator.EQ, OrgUnitFactory.ORGUNIT_CONTENT_TYPE); 099 String xPathQuery = QueryHelper.getXPathQuery(null, OrgUnitFactory.ORGUNIT_NODETYPE, expr); 100 AmetysObjectIterable<OrgUnit> orgUnits = _resolver.query(xPathQuery); 101 102 List<String> excludedOrgunits = Arrays.asList(zoneItem.getServiceParameters().getValue("excludedOrgunits")); 103 104 orgUnits.stream() 105 .filter(ou -> !_rootOrgUnitProvider.isRoot(ou) && !excludedOrgunits.contains(ou.getId())) 106 .forEach(LambdaUtils.wrapConsumer(ou -> { 107 AttributesImpl attrs = new AttributesImpl(); 108 attrs.addCDATAAttribute("id", ou.getId()); 109 110 XMLUtils.startElement(contentHandler, "orgunit", attrs); 111 ou.dataToSAX(contentHandler, view, DataContext.newInstance().withLocale(defaultLocale).withEmptyValues(false)); 112 XMLUtils.endElement(contentHandler, "orgunit"); 113 })); 114 115 _saxSearchForm(zoneItem); 116 117 XMLUtils.endElement(contentHandler, "orgunits"); 118 119 contentHandler.endDocument(); 120 } 121 122 private void _saxSearchForm(ZoneItem zoneItem) throws SAXException 123 { 124 String criterionInputName = _getOrgUnitCriterionInputName(zoneItem); 125 if (criterionInputName != null) 126 { 127 XMLUtils.startElement(contentHandler, "search-form"); 128 XMLUtils.createElement(contentHandler, "criterion", criterionInputName); 129 XMLUtils.endElement(contentHandler, "search-form"); 130 } 131 } 132 133 private String _getOrgUnitCriterionInputName(ZoneItem zoneItem) 134 { 135 String searchPageId = zoneItem.getServiceParameters().getValue("search-page"); 136 if (StringUtils.isNotEmpty(searchPageId)) 137 { 138 Page page = _resolver.resolveById(searchPageId); 139 if (page.getType() == PageType.CONTAINER) 140 { 141 Optional< ? extends ZoneItem> searchZoneItem = page.getZones().stream() 142 .flatMap(z -> z.getZoneItems().stream()) 143 .filter(zi -> zi.getType() == ZoneType.SERVICE) 144 .filter(zi -> zi.getServiceId().equals(SearchService.ROLE)) 145 .findFirst(); 146 147 if (searchZoneItem.isPresent()) 148 { 149 SearchServiceInstance serviceInstance = _searchServiceInstanceManager.get(searchZoneItem.get().getId()); 150 return serviceInstance.getCriterionTree() 151 .map(AbstractTreeNode::getFlatLeaves) 152 .orElseGet(Collections::emptyList) 153 .stream() 154 .map(TreeLeaf::getValue) 155 .filter(c -> StringUtils.endsWith(c.getCriterionDefinition().getName(), "$org.ametys.plugins.odf.Content.abstractProgram$orgUnit")) 156 .findFirst() 157 .map(c -> c.getName()) 158 .orElseGet(null); 159 160 } 161 } 162 } 163 164 return null; 165 } 166 167}