/*
* (C) Copyright 2015 Nuxeo SA (http://nuxeo.com/) and others.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Contributors:
* Thomas Roger
*/
package org.nuxeo.ecm.permissions;
import static org.nuxeo.ecm.permissions.Constants.ACE_GRANTED_TEMPLATE;
import static org.nuxeo.ecm.permissions.Constants.ACE_INFO_COMMENT;
import static org.nuxeo.ecm.permissions.Constants.ACE_INFO_DIRECTORY;
import static org.nuxeo.ecm.permissions.Constants.ACE_KEY;
import static org.nuxeo.ecm.permissions.Constants.ACL_NAME_KEY;
import static org.nuxeo.ecm.permissions.Constants.PERMISSION_NOTIFICATION_EVENT;
import java.util.Collections;
import java.util.Locale;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.nuxeo.common.utils.i18n.I18NUtils;
import org.nuxeo.ecm.automation.AutomationService;
import org.nuxeo.ecm.automation.OperationChain;
import org.nuxeo.ecm.automation.OperationContext;
import org.nuxeo.ecm.automation.OperationException;
import org.nuxeo.ecm.automation.core.operations.notification.SendMail;
import org.nuxeo.ecm.automation.core.scripting.Expression;
import org.nuxeo.ecm.automation.core.scripting.Scripting;
import org.nuxeo.ecm.automation.core.util.StringList;
import org.nuxeo.ecm.automation.features.PlatformFunctions;
import org.nuxeo.ecm.core.api.CoreSession;
import org.nuxeo.ecm.core.api.DocumentModel;
import org.nuxeo.ecm.core.api.NuxeoGroup;
import org.nuxeo.ecm.core.api.NuxeoPrincipal;
import org.nuxeo.ecm.core.api.security.ACE;
import org.nuxeo.ecm.core.event.Event;
import org.nuxeo.ecm.core.event.EventBundle;
import org.nuxeo.ecm.core.event.EventContext;
import org.nuxeo.ecm.core.event.PostCommitFilteringEventListener;
import org.nuxeo.ecm.core.event.impl.DocumentEventContext;
import org.nuxeo.ecm.directory.Session;
import org.nuxeo.ecm.directory.api.DirectoryService;
import org.nuxeo.ecm.platform.ec.notification.service.NotificationService;
import org.nuxeo.ecm.platform.ec.notification.service.NotificationServiceHelper;
import org.nuxeo.ecm.platform.usermanager.UserManager;
import org.nuxeo.ecm.tokenauth.service.TokenAuthenticationService;
import org.nuxeo.runtime.api.Framework;
/**
* Listener sending an email notification for a granted ACE.
* <p>
* This listener checks only if the ACE is granted. It assumes that other checks (such as the ACE becomes effective)
* have been done before.
*
* @since 7.4
*/
public class PermissionGrantedNotificationListener implements PostCommitFilteringEventListener {
public static final String LABEL_SUBJECT_NEW_PERMISSION = "label.subject.new.permission";
private static final Log log = LogFactory.getLog(PermissionGrantedNotificationListener.class);
public static final String SUBJECT_FORMAT = "%s %s";
@Override
public void handleEvent(EventBundle events) {
for (Event event : events) {
handleEvent(event);
}
}
protected void handleEvent(Event event) {
EventContext eventCtx = event.getContext();
if (!(eventCtx instanceof DocumentEventContext)) {
return;
}
DocumentEventContext docCtx = (DocumentEventContext) eventCtx;
CoreSession coreSession = docCtx.getCoreSession();
DocumentModel doc = docCtx.getSourceDocument();
if (doc == null || !coreSession.exists(doc.getRef())) {
return;
}
ACE ace = (ACE) docCtx.getProperty(ACE_KEY);
String aclName = (String) docCtx.getProperty(ACL_NAME_KEY);
if (ace == null || ace.isDenied() || aclName == null) {
return;
}
String username = ace.getUsername();
StringList to = getRecipients(username);
if (to == null) {
// no recipient
return;
}
Expression from = Scripting.newExpression("Env[\"mail.from\"]");
NotificationService notificationService = NotificationServiceHelper.getNotificationService();
String subject = String.format(SUBJECT_FORMAT, notificationService.getEMailSubjectPrefix(),
I18NUtils.getMessageString("messages", LABEL_SUBJECT_NEW_PERMISSION, new Object[] { doc.getTitle() },
Locale.ENGLISH));
try (OperationContext ctx = new OperationContext(coreSession)) {
ctx.setInput(doc);
ctx.put("ace", ace);
Framework.doPrivileged(() -> {
DirectoryService directoryService = Framework.getService(DirectoryService.class);
try (Session session = directoryService.open(ACE_INFO_DIRECTORY)) {
String id = PermissionHelper.computeDirectoryId(doc, aclName, ace.getId());
DocumentModel entry = session.getEntry(id);
if (entry != null) {
String comment = (String) entry.getPropertyValue(ACE_INFO_COMMENT);
if (comment != null) {
comment = StringEscapeUtils.escapeHtml(comment);
comment = comment.replaceAll("\n", "<br/>");
ctx.put("comment", comment);
}
}
}
});
String aceCreator = ace.getCreator();
if (aceCreator != null) {
UserManager userManager = Framework.getService(UserManager.class);
NuxeoPrincipal creator = userManager.getPrincipal(aceCreator);
if (creator != null) {
ctx.put("aceCreator", String.format("%s (%s)", principalFullName(creator), creator.getName()));
}
}
if (NuxeoPrincipal.isTransientUsername(username)) {
TokenAuthenticationService tokenAuthenticationService = Framework
.getService(TokenAuthenticationService.class);
String token = tokenAuthenticationService.getToken(username, doc.getRepositoryName(), doc.getId());
if (token != null) {
ctx.put("token", token);
}
}
OperationChain chain = new OperationChain("SendMail");
chain.add(SendMail.ID).set("from", from).set("to", to).set("HTML", true).set("subject", subject)
.set("message", ACE_GRANTED_TEMPLATE);
Framework.getService(AutomationService.class).run(ctx, chain);
} catch (OperationException e) {
log.warn("Unable to notify user", e);
log.debug(e, e);
}
}
// copied from org.nuxeo.ecm.platform.ui.web.tag.fn.Functions which lives in nuxeo-platform-ui-web
public static String principalFullName(NuxeoPrincipal principal) {
String first = principal.getFirstName();
String last = principal.getLastName();
return userDisplayName(principal.getName(), first, last);
}
public static String userDisplayName(String id, String first, String last) {
if (first == null || first.length() == 0) {
if (last == null || last.length() == 0) {
return id;
} else {
return last;
}
} else {
if (last == null || last.length() == 0) {
return first;
} else {
return first + ' ' + last;
}
}
}
protected StringList getRecipients(String username) {
UserManager userManager = Framework.getService(UserManager.class);
NuxeoPrincipal principal = userManager.getPrincipal(username);
StringList to = null;
if (principal != null) {
to = new StringList(Collections.singletonList(principal.getEmail()));
} else {
NuxeoGroup group = userManager.getGroup(username);
if (group != null) {
PlatformFunctions platformFunctions = new PlatformFunctions();
to = platformFunctions.getEmailsFromGroup(group.getName());
}
}
return to;
}
@Override
public boolean acceptEvent(Event event) {
String eventName = event.getName();
return PERMISSION_NOTIFICATION_EVENT.equals(eventName);
}
}