001/* 002 * Copyright 2016 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.documents.generators; 017 018import java.io.IOException; 019import java.util.Optional; 020import java.util.Set; 021 022import org.apache.avalon.framework.context.Context; 023import org.apache.avalon.framework.context.ContextException; 024import org.apache.avalon.framework.context.Contextualizable; 025import org.apache.avalon.framework.service.ServiceException; 026import org.apache.avalon.framework.service.ServiceManager; 027import org.apache.cocoon.ProcessingException; 028import org.apache.cocoon.generation.ServiceableGenerator; 029import org.apache.cocoon.xml.AttributesImpl; 030import org.apache.cocoon.xml.XMLUtils; 031import org.apache.commons.lang3.StringUtils; 032import org.xml.sax.SAXException; 033 034import org.ametys.cms.search.Sort; 035import org.ametys.cms.search.Sort.Order; 036import org.ametys.cms.search.query.DocumentTypeQuery; 037import org.ametys.cms.search.solr.SearcherFactory; 038import org.ametys.cms.transformation.xslt.ResolveURIComponent; 039import org.ametys.core.right.RightManager; 040import org.ametys.core.user.CurrentUserProvider; 041import org.ametys.core.user.UserIdentity; 042import org.ametys.core.user.UserManager; 043import org.ametys.core.util.DateUtils; 044import org.ametys.core.util.LambdaUtils; 045import org.ametys.plugins.core.user.UserHelper; 046import org.ametys.plugins.explorer.resources.Resource; 047import org.ametys.plugins.explorer.resources.ResourceCollection; 048import org.ametys.plugins.repository.AmetysObjectIterable; 049import org.ametys.plugins.workspaces.documents.DocumentWorkspaceModule; 050import org.ametys.plugins.workspaces.indexing.solr.SolrWorkspacesConstants; 051import org.ametys.plugins.workspaces.members.ProjectMemberManager; 052import org.ametys.plugins.workspaces.project.ProjectManager; 053import org.ametys.plugins.workspaces.project.ProjectsCatalogueManager; 054import org.ametys.plugins.workspaces.project.modules.WorkspaceModuleExtensionPoint; 055import org.ametys.plugins.workspaces.project.objects.Project; 056import org.ametys.web.repository.page.Page; 057 058/** 059 * Document stream generator for the simple service. 060 */ 061public class DocumentStreamGenerator extends ServiceableGenerator implements Contextualizable 062{ 063 /** The project manager */ 064 protected ProjectManager _projectManager; 065 066 /** The project member manager */ 067 protected ProjectMemberManager _projectMemberManager; 068 069 /** The project catalog helper */ 070 protected ProjectsCatalogueManager _projectCatalogManager; 071 072 /** The document manager */ 073 protected DocumentWorkspaceModule _documentModule; 074 075 /** Current user provider */ 076 protected CurrentUserProvider _currentUserProvider; 077 078 /** The searcher factory */ 079 protected SearcherFactory _searcherFactory; 080 081 /** The user manager */ 082 protected UserManager _userManager; 083 084 /** The user helper */ 085 protected UserHelper _userHelper; 086 087 /** The right manager */ 088 protected RightManager _rightManager; 089 090 /** Avalon context */ 091 protected Context _context; 092 093 @Override 094 public void contextualize(Context context) throws ContextException 095 { 096 _context = context; 097 } 098 099 @Override 100 public void service(ServiceManager serviceManager) throws ServiceException 101 { 102 _projectManager = (ProjectManager) serviceManager.lookup(ProjectManager.ROLE); 103 _projectMemberManager = (ProjectMemberManager) serviceManager.lookup(ProjectMemberManager.ROLE); 104 _projectCatalogManager = (ProjectsCatalogueManager) serviceManager.lookup(ProjectsCatalogueManager.ROLE); 105 WorkspaceModuleExtensionPoint moduleManagerEP = (WorkspaceModuleExtensionPoint) serviceManager.lookup(WorkspaceModuleExtensionPoint.ROLE); 106 _documentModule = moduleManagerEP.getModule(DocumentWorkspaceModule.DOCUMENT_MODULE_ID); 107 _currentUserProvider = (CurrentUserProvider) serviceManager.lookup(CurrentUserProvider.ROLE); 108 _searcherFactory = (SearcherFactory) serviceManager.lookup(SearcherFactory.ROLE); 109 _userManager = (UserManager) serviceManager.lookup(UserManager.ROLE); 110 _userHelper = (UserHelper) serviceManager.lookup(UserHelper.ROLE); 111 _rightManager = (RightManager) serviceManager.lookup(RightManager.ROLE); 112 } 113 114 @Override 115 public void generate() throws IOException, SAXException, ProcessingException 116 { 117 int max = parameters.getParameterAsInteger("max-results", 0); 118 119 contentHandler.startDocument(); 120 XMLUtils.startElement(contentHandler, "documents"); 121 122 UserIdentity user = _currentUserProvider.getUser(); 123 124 if (user != null) 125 { 126 _getLastDocuments(user, max).stream().forEach(this::_saxDocument); 127 } 128 129 XMLUtils.endElement(contentHandler, "documents"); 130 contentHandler.endDocument(); 131 } 132 133 private AmetysObjectIterable<Resource> _getLastDocuments(UserIdentity user, int max) 134 { 135 try 136 { 137 return _searcherFactory.create() 138 .addFilterQuery(new DocumentTypeQuery(SolrWorkspacesConstants.TYPE_PROJECT_RESOURCE)) 139 .setCheckRights(true) 140 .withLimits(0, max > 0 ? max : Integer.MAX_VALUE) 141 .withSort(new Sort("date-for-sorting", Order.DESC)) 142 .search(); 143 } 144 catch (Exception e) 145 { 146 throw new RuntimeException(String.format("An error occurred while requesting last documents for user '%s'.", user), e); 147 } 148 } 149 150 /** 151 * SAX necessary document properties for the simple document stream service. 152 * @param resource The resource 153 */ 154 protected void _saxDocument(Resource resource) 155 { 156 try 157 { 158 Project project = _projectManager.getParentProject(resource); 159 ResourceCollection folder = resource.getParent(); 160 161 AttributesImpl attrs = new AttributesImpl(); 162 163 attrs.addCDATAAttribute("id", resource.getId()); 164 XMLUtils.startElement(contentHandler, "document", attrs); 165 166 XMLUtils.createElement(contentHandler, "name", resource.getName()); 167 168 attrs.clear(); 169 attrs.addCDATAAttribute("id", folder.getId()); 170 String documentUrl = _getDocumentUrl(project, folder); 171 attrs.addCDATAAttribute("url", documentUrl); 172 XMLUtils.createElement(contentHandler, "folder", attrs, folder.getName()); 173 174 attrs.clear(); 175 attrs.addCDATAAttribute("id", project.getId()); 176 Optional<UserIdentity> creator = Optional.ofNullable(resource.getCreator()); 177 attrs.addCDATAAttribute("hasAccess", String.valueOf(creator.isPresent() && _projectMemberManager.isProjectMember(project, creator.get()))); 178 attrs.addCDATAAttribute("url", _projectManager.getProjectUrl(project, StringUtils.EMPTY)); 179 XMLUtils.createElement(contentHandler, "project", attrs, project.getTitle()); 180 181 _projectCatalogManager.saxCategory(contentHandler, project, "projectCategory"); 182 183 // Last modification: date and user 184 XMLUtils.createElement(contentHandler, "lastModified", DateUtils.dateToString(resource.getLastModified())); 185 186 creator.map(_userManager::getUser) 187 .ifPresent(LambdaUtils.wrapConsumer(lastContributor -> _userHelper.saxUser(lastContributor, contentHandler))); 188 189 XMLUtils.endElement(contentHandler, "document"); 190 } 191 catch (SAXException e) 192 { 193 throw new RuntimeException("An error occurred while gathering the documents' information."); 194 } 195 } 196 197 /** 198 * Retrieves the URL of a folder in the document module of a project 199 * @param project The project 200 * @param folder The folder 201 * @return The url or null if no module page is found for this project and the current language 202 */ 203 protected String _getDocumentUrl(Project project, ResourceCollection folder) 204 { 205 Set<Page> documentModulePages = _projectManager.getModulePages(project, _documentModule); 206 if (!documentModulePages.isEmpty()) 207 { 208 Page documentModulePage = documentModulePages.iterator().next(); 209 StringBuilder sb = new StringBuilder(); 210 sb.append(ResolveURIComponent.resolve("page", documentModulePage.getId())); 211 sb.append("#").append(folder.getId()); 212 return sb.toString(); 213 } 214 215 return null; 216 } 217}