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; 020 021import org.apache.avalon.framework.context.Context; 022import org.apache.avalon.framework.context.ContextException; 023import org.apache.avalon.framework.context.Contextualizable; 024import org.apache.avalon.framework.service.ServiceException; 025import org.apache.avalon.framework.service.ServiceManager; 026import org.apache.cocoon.ProcessingException; 027import org.apache.cocoon.components.ContextHelper; 028import org.apache.cocoon.environment.Request; 029import org.apache.cocoon.generation.ServiceableGenerator; 030import org.apache.cocoon.xml.AttributesImpl; 031import org.apache.cocoon.xml.XMLUtils; 032import org.apache.commons.lang3.StringUtils; 033import org.xml.sax.SAXException; 034 035import org.ametys.cms.search.Sort; 036import org.ametys.cms.search.Sort.Order; 037import org.ametys.cms.search.query.DocumentTypeQuery; 038import org.ametys.cms.search.solr.SearcherFactory; 039import org.ametys.cms.transformation.xslt.ResolveURIComponent; 040import org.ametys.core.right.RightManager; 041import org.ametys.core.user.CurrentUserProvider; 042import org.ametys.core.user.UserIdentity; 043import org.ametys.core.user.UserManager; 044import org.ametys.core.util.DateUtils; 045import org.ametys.core.util.LambdaUtils; 046import org.ametys.plugins.core.user.UserHelper; 047import org.ametys.plugins.explorer.resources.Resource; 048import org.ametys.plugins.explorer.resources.ResourceCollection; 049import org.ametys.plugins.repository.AmetysObjectIterable; 050import org.ametys.plugins.workspaces.documents.DocumentWorkspaceModule; 051import org.ametys.plugins.workspaces.indexing.solr.SolrWorkspacesConstants; 052import org.ametys.plugins.workspaces.members.ProjectMemberManager; 053import org.ametys.plugins.workspaces.project.ProjectManager; 054import org.ametys.plugins.workspaces.project.modules.WorkspaceModuleExtensionPoint; 055import org.ametys.plugins.workspaces.project.objects.Project; 056import org.ametys.web.WebConstants; 057import org.ametys.web.repository.page.Page; 058 059import com.google.common.collect.Iterables; 060 061/** 062 * Document stream generator for the simple service. 063 */ 064public class DocumentStreamGenerator extends ServiceableGenerator implements Contextualizable 065{ 066 /** The project manager */ 067 protected ProjectManager _projectManager; 068 069 /** The project member manager */ 070 protected ProjectMemberManager _projectMemberManager; 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 094 @Override 095 public void contextualize(Context context) throws ContextException 096 { 097 _context = context; 098 } 099 100 @Override 101 public void service(ServiceManager serviceManager) throws ServiceException 102 { 103 _projectManager = (ProjectManager) serviceManager.lookup(ProjectManager.ROLE); 104 _projectMemberManager = (ProjectMemberManager) serviceManager.lookup(ProjectMemberManager.ROLE); 105 WorkspaceModuleExtensionPoint moduleManagerEP = (WorkspaceModuleExtensionPoint) serviceManager.lookup(WorkspaceModuleExtensionPoint.ROLE); 106 _documentModule = moduleManagerEP.getModule(DocumentWorkspaceModule.DODUMENT_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", Iterables.getFirst(_projectManager.getProjectUrls(project), StringUtils.EMPTY)); 179 XMLUtils.createElement(contentHandler, "project", attrs, project.getTitle()); 180 // Last modification: date and user 181 XMLUtils.createElement(contentHandler, "lastModified", DateUtils.dateToString(resource.getLastModified())); 182 183 creator.map(_userManager::getUser) 184 .ifPresent(LambdaUtils.wrapConsumer(lastContributor -> _userHelper.saxUser(lastContributor, contentHandler))); 185 186 XMLUtils.endElement(contentHandler, "document"); 187 } 188 catch (SAXException e) 189 { 190 throw new RuntimeException("An error occurred while gathering the documents' information."); 191 } 192 } 193 194 /** 195 * Retrieves the URL of a folder in the document module of a project 196 * @param project The project 197 * @param folder The folder 198 * @return The url or null if no module page is found for this project and the current language 199 */ 200 protected String _getDocumentUrl(Project project, ResourceCollection folder) 201 { 202 Request request = ContextHelper.getRequest(_context); 203 String language = (String) request.getAttribute(WebConstants.REQUEST_ATTR_SITEMAP_NAME); 204 205 AmetysObjectIterable<Page> documentModulePages = _documentModule.getModulePages(project, language); 206 if (documentModulePages.getSize() > 0) 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}