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.activities.documents; 017 018import java.util.ArrayList; 019import java.util.List; 020import java.util.Map; 021import java.util.stream.Stream; 022 023import javax.jcr.RepositoryException; 024 025import org.apache.avalon.framework.service.ServiceException; 026import org.apache.avalon.framework.service.ServiceManager; 027 028import org.ametys.core.observation.Event; 029import org.ametys.core.util.I18nUtils; 030import org.ametys.plugins.explorer.ObservationConstants; 031import org.ametys.plugins.explorer.resources.Resource; 032import org.ametys.plugins.explorer.resources.ResourceCollection; 033import org.ametys.plugins.repository.AmetysObject; 034import org.ametys.plugins.repository.AmetysObjectResolver; 035import org.ametys.plugins.repository.activities.Activity; 036import org.ametys.plugins.repository.activities.ActivityType; 037import org.ametys.plugins.repository.query.expression.Expression; 038import org.ametys.plugins.repository.query.expression.Expression.Operator; 039import org.ametys.plugins.repository.query.expression.ExpressionContext; 040import org.ametys.plugins.repository.query.expression.OrExpression; 041import org.ametys.plugins.repository.query.expression.StringExpression; 042import org.ametys.plugins.workspaces.activities.AbstractWorkspacesActivityType; 043import org.ametys.plugins.workspaces.activities.documents.AbstractResourceReferenceElementType.ResourceReference; 044import org.ametys.plugins.workspaces.documents.DocumentWorkspaceModule; 045import org.ametys.plugins.workspaces.project.modules.WorkspaceModuleExtensionPoint; 046import org.ametys.plugins.workspaces.project.notification.ResourceNotifierHelper; 047import org.ametys.plugins.workspaces.project.objects.Project; 048import org.ametys.runtime.i18n.I18nizableText; 049 050/** 051 * {@link ActivityType} implementation for documents-related activities 052 */ 053public class DocumentsActivityType extends AbstractWorkspacesActivityType 054{ 055 /** data name for the parent folder path in explorer */ 056 public static final String PARENT_FOLDER_PATH = "parentPath"; 057 058 /** data name for the document parent folder id */ 059 public static final String PARENT_FOLDER_ID = "parentFolderId"; 060 061 /** data name for the document parent folder name */ 062 public static final String PARENT_FOLDER = "parentFolder"; 063 064 /** data name for the activity file */ 065 public static final String FILE_DATA_NAME = "file"; 066 067 /** data name for the activity files */ 068 public static final String FILES_DATA_NAME = "files"; 069 070 /** Constant for event's category */ 071 public static final String EVENT_CATEGORY_DOCUMENTS = "documents"; 072 073 /** Resolver for Ametys objects */ 074 protected AmetysObjectResolver _ametysObjectResolver; 075 076 private I18nUtils _i18nUtils; 077 078 private DocumentWorkspaceModule _documentModule; 079 080 private ResourceNotifierHelper _resourceNotifierHelper; 081 082 083 @Override 084 public void service(ServiceManager serviceManager) throws ServiceException 085 { 086 super.service(serviceManager); 087 _ametysObjectResolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE); 088 _i18nUtils = (I18nUtils) serviceManager.lookup(I18nUtils.ROLE); 089 WorkspaceModuleExtensionPoint moduleManagerEP = (WorkspaceModuleExtensionPoint) serviceManager.lookup(WorkspaceModuleExtensionPoint.ROLE); 090 _documentModule = moduleManagerEP.getModule(DocumentWorkspaceModule.DOCUMENT_MODULE_ID); 091 _resourceNotifierHelper = (ResourceNotifierHelper) serviceManager.lookup(ResourceNotifierHelper.ROLE); 092 } 093 094 @Override 095 public boolean support(Event event) 096 { 097 return !event.getId().equals(ObservationConstants.EVENT_RESOURCE_UPDATED) 098 || _isResourceRecentlyModified(event); 099 } 100 101 private boolean _isResourceRecentlyModified(Event event) 102 { 103 String resourceId = (String) event.getArguments().getOrDefault(ObservationConstants.ARGS_ID, null); 104 return !_resourceNotifierHelper.resourceRecentlyModified(resourceId); 105 } 106 107 @Override 108 public void setAdditionalActivityData(Activity activity, Map<String, Object> parameters) throws RepositoryException 109 { 110 super.setAdditionalActivityData(activity, parameters); 111 112 activity.setValue(PROJECT_CATEGORY, EVENT_CATEGORY_DOCUMENTS); 113 114 String folderId = (String) parameters.get(ObservationConstants.ARGS_PARENT_ID); 115 ResourceCollection parentFolder = null; 116 if (folderId == null) 117 { 118 String resourceId = (String) parameters.get(ObservationConstants.ARGS_ID); 119 Resource resource = _ametysObjectResolver.resolveById(resourceId); 120 parentFolder = resource.getParent(); 121 folderId = parentFolder.getId(); 122 } 123 else 124 { 125 parentFolder = _ametysObjectResolver.resolveById(folderId); 126 } 127 activity.setValue(PARENT_FOLDER_ID, folderId); 128 129 // Parent name 130 String parentFolderName = parentFolder.getName(); 131 if ("ametys-internal:resources".equals(parentFolderName)) 132 { 133 parentFolderName = _i18nUtils.translate(new I18nizableText("plugin.explorer", "PLUGINS_EXPLORER_ROOT_NODE")); 134 } 135 activity.setValue(PARENT_FOLDER, parentFolderName); 136 137 activity.setValue(PARENT_FOLDER_PATH, parentFolder.getExplorerPath()); 138 } 139 140 @Override 141 public Map<String, Object> additionnalDataToJSONForClient(Activity activity) 142 { 143 Map<String, Object> json = super.additionnalDataToJSONForClient(activity); 144 String parentId = activity.getValue(PARENT_FOLDER_ID); 145 146 String projectName = activity.getValue(PROJECT_NAME); 147 Project project = _projectManager.getProject(projectName); 148 if (project != null) 149 { 150 json.put("parentFolderUrl", _documentModule.getFolderUri(project, parentId)); 151 } 152 return json; 153 } 154 155 @Override 156 public boolean isMergeable(Activity activity1, Activity activity2) 157 { 158 if (!super.isMergeable(activity1, activity2)) 159 { 160 return false; 161 } 162 String parentFolder1 = activity1.getValue(PARENT_FOLDER_ID); 163 String parentFolder2 = activity2.getValue(PARENT_FOLDER_ID); 164 165 return parentFolder1 != null && parentFolder2 != null && parentFolder1.equals(parentFolder2); 166 } 167 168 @Override 169 public Expression getFilterPatternExpression(String pattern) 170 { 171 Expression folderExpr = new StringExpression(PARENT_FOLDER, Operator.WD, pattern, ExpressionContext.newInstance().withCaseInsensitive(true)); 172 Expression filesExpr = new StringExpression(FILES_DATA_NAME + "/*/name", Operator.WD, pattern, ExpressionContext.newInstance().withCaseInsensitive(true)); 173 Expression fileExpr = new StringExpression(FILE_DATA_NAME + "/name", Operator.WD, pattern, ExpressionContext.newInstance().withCaseInsensitive(true)); 174 175 return new OrExpression(folderExpr, filesExpr, fileExpr); 176 } 177 178 @SuppressWarnings("unchecked") 179 @Override 180 public Map<String, Object> mergeActivities(List<Activity> activities) 181 { 182 Map<String, Object> mergedActivities = super.mergeActivities(activities); 183 184 List<Map<String, Object>> files = new ArrayList<>(); 185 186 List<String> knownFiles = new ArrayList<>(); 187 188 for (Activity activity : activities) 189 { 190 Map<String, Object> json = activity.toJSONForClient(); 191 if (json.containsKey(FILE_DATA_NAME)) 192 { 193 Map<String, Object> file = (Map<String, Object>) json.get(FILE_DATA_NAME); 194 if (!knownFiles.contains(file.get("id"))) 195 { 196 files.add((Map<String, Object>) json.get(FILE_DATA_NAME)); 197 knownFiles.add((String) file.get("id")); 198 } 199 } 200 else if (json.containsKey(FILES_DATA_NAME)) 201 { 202 files.addAll((List<Map<String, Object>>) json.get("files")); 203 } 204 } 205 206 if (files.size() > 0) 207 { 208 mergedActivities.put("files", files); 209 } 210 211 mergedActivities.put("amount", files.size()); 212 213 return mergedActivities; 214 } 215 216 @Override 217 public Project getProjectFromEvent(Event event) 218 { 219 Map<String, Object> args = event.getArguments(); 220 String parentId = (String) args.get(ObservationConstants.ARGS_PARENT_ID); 221 if (parentId != null) 222 { 223 return getParentProject(_resolver.resolveById(parentId)); 224 } 225 else 226 { 227 String resourceId = (String) args.get(ObservationConstants.ARGS_ID); 228 Resource resource = _resolver.resolveById(resourceId); 229 return getParentProject(resource.getParent()); 230 } 231 } 232 233 @Override 234 public AmetysObject getTargetAmetysObject(Activity activity) 235 { 236 return _resolver.resolveById(activity.getValue(DocumentsActivityType.PARENT_FOLDER_ID)); 237 } 238 @Override 239 public String getMailBodyURI(Activity activity) 240 { 241 return "cocoon://_plugins/workspaces/notification-mail-resource"; 242 } 243 244 @Override 245 public String getSubjectI18nKey(Activity activity) 246 { 247 String i18nKey = super.getSubjectI18nKey(activity); 248 if (activity.hasValue(DocumentsActivityType.FILES_DATA_NAME)) 249 { 250 ResourceReference[] refs = activity.getValue(DocumentsActivityType.FILES_DATA_NAME); 251 if (refs.length > 1) 252 { 253 i18nKey += "_MULTIPLE"; 254 } 255 } 256 return i18nKey; 257 } 258 259 @Override 260 public List<String> getSubjectI18nParams(Activity activity) 261 { 262 List<String> i18nParams = super.getSubjectI18nParams(activity); 263 264 if (activity.hasValue(DocumentsActivityType.FILE_DATA_NAME)) 265 { 266 ResourceReference ref = activity.getValue(DocumentsActivityType.FILE_DATA_NAME); 267 i18nParams.add(ref.oldName() != null ? ref.oldName() : ref.name()); // {1} 268 } 269 else if (activity.hasValue(DocumentsActivityType.FILES_DATA_NAME)) 270 { 271 ResourceReference[] refs = activity.getValue(DocumentsActivityType.FILES_DATA_NAME); 272 if (refs.length > 1) 273 { 274 i18nParams.add(String.valueOf(refs.length)); // {1} 275 } 276 else 277 { 278 i18nParams.add(Stream.of(refs).findFirst().map(ResourceReference::name).orElse("")); // {1} 279 } 280 } 281 return i18nParams; 282 } 283}