001/* 002 * Copyright 2010 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.project.notification; 017 018import java.util.ArrayList; 019import java.util.List; 020import java.util.Map; 021import java.util.Set; 022 023import javax.mail.MessagingException; 024 025import org.apache.avalon.framework.context.Context; 026import org.apache.avalon.framework.context.ContextException; 027import org.apache.avalon.framework.context.Contextualizable; 028import org.apache.avalon.framework.service.ServiceException; 029import org.apache.avalon.framework.service.ServiceManager; 030import org.apache.avalon.framework.service.Serviceable; 031import org.apache.commons.collections.CollectionUtils; 032import org.apache.commons.lang.StringUtils; 033 034import org.ametys.cms.transformation.xslt.ResolveURIComponent; 035import org.ametys.core.observation.Event; 036import org.ametys.core.observation.Observer; 037import org.ametys.core.right.RightManager; 038import org.ametys.core.user.User; 039import org.ametys.core.user.UserIdentity; 040import org.ametys.core.user.UserManager; 041import org.ametys.core.util.I18nUtils; 042import org.ametys.core.util.mail.SendMailHelper; 043import org.ametys.plugins.explorer.ObservationConstants; 044import org.ametys.plugins.repository.AmetysObject; 045import org.ametys.plugins.repository.AmetysObjectResolver; 046import org.ametys.plugins.workspaces.project.ProjectManager; 047import org.ametys.plugins.workspaces.project.modules.WorkspaceModule; 048import org.ametys.plugins.workspaces.project.modules.WorkspaceModuleExtensionPoint; 049import org.ametys.plugins.workspaces.project.objects.Project; 050import org.ametys.runtime.config.Config; 051import org.ametys.runtime.i18n.I18nizableText; 052import org.ametys.runtime.plugin.component.AbstractLogEnabled; 053import org.ametys.runtime.plugin.component.PluginAware; 054import org.ametys.web.renderingcontext.RenderingContext; 055import org.ametys.web.renderingcontext.RenderingContextHandler; 056import org.ametys.web.repository.page.Page; 057 058import com.google.common.collect.Iterables; 059 060/** 061 * {@link Observer} for observing events on resources project 062 */ 063public abstract class AbstractSendNotificationObserver extends AbstractLogEnabled implements Observer, Serviceable, Contextualizable, PluginAware 064{ 065 /** The Ametys Object Resolver*/ 066 protected AmetysObjectResolver _resolver; 067 /** The avalon context */ 068 protected Context _context; 069 /** The users manager */ 070 protected UserManager _userManager; 071 /** The rights manager */ 072 protected RightManager _rightManager; 073 /** The i18n utils */ 074 protected I18nUtils _i18nUtils; 075 /** The project manager */ 076 protected ProjectManager _projectManager; 077 /** The rendering context handler */ 078 protected RenderingContextHandler _renderingContextHandler; 079 /** The name of current plugin */ 080 protected String _pluginName; 081 /** The workspace module managers EP */ 082 protected WorkspaceModuleExtensionPoint _moduleManagerEP; 083 084 @Override 085 public void service(ServiceManager manager) throws ServiceException 086 { 087 _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE); 088 _userManager = (UserManager) manager.lookup(UserManager.ROLE); 089 _rightManager = (RightManager) manager.lookup(RightManager.ROLE); 090 _i18nUtils = (I18nUtils) manager.lookup(I18nUtils.ROLE); 091 _projectManager = (ProjectManager) manager.lookup(ProjectManager.ROLE); 092 _renderingContextHandler = (RenderingContextHandler) manager.lookup(RenderingContextHandler.ROLE); 093 _moduleManagerEP = (WorkspaceModuleExtensionPoint) manager.lookup(WorkspaceModuleExtensionPoint.ROLE); 094 } 095 096 @Override 097 public void contextualize(Context context) throws ContextException 098 { 099 _context = context; 100 } 101 102 public void setPluginInfo(String pluginName, String featureName, String id) 103 { 104 _pluginName = pluginName; 105 } 106 107 @Override 108 public int getPriority(Event event) 109 { 110 return Observer.MAX_PRIORITY; 111 } 112 113 @Override 114 public void observe(Event event, Map<String, Object> transientVars) 115 { 116 UserIdentity userIdentity = event.getIssuer(); 117 User user = _userManager.getUser(userIdentity.getPopulationId(), userIdentity.getLogin()); 118 119 Project project = getProject(event); 120 121 if (project != null) 122 { 123 notifyEvent(project, event.getId(), event.getArguments(), user); 124 } 125 } 126 127 /** 128 * Notify email by mail 129 * @param project The project 130 * @param eventId The id of event 131 * @param eventParams The event's arguments 132 * @param issuer The issuer 133 */ 134 protected abstract void notifyEvent (Project project, String eventId, Map<String, Object> eventParams, User issuer); 135 136 /** 137 * Get the project from event 138 * @param event The event 139 * @return the project or null if not found 140 */ 141 protected Project getProject (Event event) 142 { 143 Map<String, Object> args = event.getArguments(); 144 145 String targetId = (String) args.get(ObservationConstants.ARGS_ID); 146 String parentID = (String) args.get(ObservationConstants.ARGS_PARENT_ID); 147 148 AmetysObject object = null; 149 if (parentID != null) 150 { 151 object = _resolver.resolveById(parentID); 152 } 153 else 154 { 155 object = _resolver.resolveById(targetId); 156 } 157 158 AmetysObject parent = object.getParent(); 159 160 while (parent != null) 161 { 162 if (parent instanceof Project) 163 { 164 return (Project) parent; 165 } 166 167 parent = parent.getParent(); 168 } 169 170 return null; 171 } 172 173 /** 174 * Get the common mail parameters 175 * @param project The parent project 176 * @param issuer The user responsible of the action 177 * @param explorerNodeId the id of the explorer node. Can be null. 178 * @return an array of strings used in every mail 179 */ 180 protected List<String> getMailCommonParams(Project project, User issuer, String explorerNodeId) 181 { 182 List<String> mailBodyParams = new ArrayList<>(); 183 // {0} project title 184 mailBodyParams.add(project.getTitle()); 185 // {1} module url 186 mailBodyParams.add(getUrl(project, explorerNodeId)); 187 // {2} user full name 188 String login = issuer.getIdentity().getLogin(); 189 String populationId = issuer.getIdentity().getPopulationId(); 190 mailBodyParams.add(_userManager.getUser(populationId, login).getFullName()); 191 // {3} user email 192 mailBodyParams.add(issuer.getEmail()); 193 194 return mailBodyParams; 195 } 196 197 /** 198 * Get the module's page 199 * @param project The project 200 * @param moduleId The module 201 * @return The page or <code>null</code> if not found 202 */ 203 protected Page getModulePage(Project project, String moduleId) 204 { 205 Set<Page> pages = null; 206 207 WorkspaceModule module = _moduleManagerEP.getModule(moduleId); 208 if (module != null && _projectManager.isModuleActivated(project, moduleId)) 209 { 210 pages = _projectManager.getModulePages(project, module); 211 } 212 213 214 if (pages != null && pages.size() > 0) 215 { 216 return pages.iterator().next(); 217 } 218 219 return null; 220 } 221 222 /** 223 * Get the absolute full url of module'page 224 * @param project The project 225 * @param moduleId The module. Can not be null 226 * @param objectId The id of concerned object. Can be null. 227 * @return The 228 */ 229 protected String getModuleUrl(Project project, String moduleId, String objectId) 230 { 231 Page modulePage = getModulePage(project, moduleId); 232 if (modulePage != null) 233 { 234 RenderingContext currentContext = _renderingContextHandler.getRenderingContext(); 235 236 try 237 { 238 StringBuilder sb = new StringBuilder(); 239 240 _renderingContextHandler.setRenderingContext(RenderingContext.FRONT); 241 242 sb.append(ResolveURIComponent.resolve("page", modulePage.getId(), false, true)); 243 244 if (objectId != null) 245 { 246 sb.append("#").append(objectId); 247 } 248 249 return sb.toString(); 250 } 251 finally 252 { 253 _renderingContextHandler.setRenderingContext(currentContext); 254 } 255 } 256 else 257 { 258 return getProjectUrl(project); 259 } 260 } 261 262 /** 263 * Get the absolute url of project 264 * @param project The project 265 * @return the project's url 266 */ 267 protected String getProjectUrl(Project project) 268 { 269 return Iterables.getFirst(_projectManager.getProjectUrls(project), StringUtils.EMPTY); 270 } 271 272 273 /** 274 * Get the URL of project to insert in email body 275 * @param project The project 276 * @param objectId The id of concerned object 277 * @return The full URL 278 */ 279 protected abstract String getUrl(Project project, String objectId); 280 281 /** 282 * Sent an email 283 * @param eventId The id of event 284 * @param recipients The recipients of the mail 285 * @param mailBodyi18nKey i18n key for the body 286 * @param mailSubjecti18nKey i18n key for the subject 287 * @param mailBodyParams parameters for the body 288 * @param mailSubjectParams parameters for the subject 289 */ 290 protected void sendMail(String eventId, List<UserIdentity> recipients, String mailBodyi18nKey, String mailSubjecti18nKey, List<String> mailBodyParams, List<String> mailSubjectParams) 291 { 292 I18nizableText i18nSubject = new I18nizableText("plugin." + _pluginName, mailSubjecti18nKey, mailSubjectParams); 293 String subject = _i18nUtils.translate(i18nSubject); 294 295 I18nizableText i18nBody = new I18nizableText("plugin." + _pluginName, mailBodyi18nKey, mailBodyParams); 296 String body = _i18nUtils.translate(i18nBody); 297 298 String sender = Config.getInstance().getValue("smtp.mail.from"); 299 300 for (UserIdentity userIdentity : recipients) 301 { 302 User recipient = _userManager.getUser(userIdentity.getPopulationId(), userIdentity.getLogin()); 303 if (recipient != null) 304 { 305 String email = recipient.getEmail(); 306 if (StringUtils.isNotEmpty(email)) 307 { 308 try 309 { 310 SendMailHelper.sendMail(subject, null, body, email, sender, true); 311 } 312 catch (MessagingException e) 313 { 314 getLogger().warn("Could not send a notification e-mail to " + email, e); 315 } 316 } 317 } 318 } 319 } 320 321 /** 322 * Get the users allowed to be notified 323 * @param eventId The id of event 324 * @param object The object on which to test rights 325 * @return The allowed users 326 */ 327 protected List<UserIdentity> getUsersToNotify(String eventId, AmetysObject object) 328 { 329 boolean returnAll = Config.getInstance().getValue("runtime.mail.massive.sending"); 330 Set<UserIdentity> readAccessUsers = _rightManager.getReadAccessAllowedUsers(object).resolveAllowedUsers(returnAll); 331 Set<UserIdentity> mailAllowedUsers = _rightManager.getAllowedUsers(getRightIdForNotify(), object).resolveAllowedUsers(returnAll); 332 333 return (List<UserIdentity>) CollectionUtils.retainAll(readAccessUsers, mailAllowedUsers); 334 } 335 336 /** 337 * Get the right to check allowed users to notify by mail 338 * @return the right id to check 339 */ 340 protected abstract String getRightIdForNotify(); 341 342 /** 343 * format the path without the root path 344 * @param rootPath The root path to remove 345 * @param path The absolute path 346 * @return the local path 347 */ 348 protected String _getPath (String rootPath, String path) 349 { 350 int index = path.indexOf(rootPath); 351 return path.substring(index + rootPath.length()); 352 } 353}