001/*
002 * (C) Copyright 2012 Nuxeo SA (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     Nuxeo - initial API and implementation
016 */
017package org.nuxeo.ecm.platform.routing.core.listener;
018
019import java.util.List;
020
021import org.nuxeo.ecm.core.api.CoreSession;
022import org.nuxeo.ecm.core.api.DocumentModel;
023import org.nuxeo.ecm.core.api.IdRef;
024import org.nuxeo.ecm.core.api.security.ACE;
025import org.nuxeo.ecm.core.api.security.ACL;
026import org.nuxeo.ecm.core.api.security.ACP;
027import org.nuxeo.ecm.core.api.security.SecurityConstants;
028import org.nuxeo.ecm.core.event.Event;
029import org.nuxeo.ecm.core.event.EventContext;
030import org.nuxeo.ecm.core.event.EventListener;
031import org.nuxeo.ecm.core.event.impl.DocumentEventContext;
032import org.nuxeo.ecm.platform.ec.notification.NotificationConstants;
033import org.nuxeo.ecm.platform.routing.api.DocumentRoutingConstants;
034import org.nuxeo.ecm.platform.routing.api.DocumentRoutingService;
035import org.nuxeo.ecm.platform.task.Task;
036import org.nuxeo.ecm.platform.task.TaskEventNames;
037import org.nuxeo.runtime.api.Framework;
038
039/**
040 * Grants the READ/WRITE permissions on the route instance to all task actors. This is needed beacuse an user having a
041 * task assigned should be able to see the relatedRoute and to set global workflow variables.
042 *
043 * @author mcedica
044 */
045public class RoutingTaskSecurityUpdaterListener implements EventListener {
046
047    @Override
048    public void handleEvent(Event event) {
049        EventContext eventCtx = event.getContext();
050        if (!(eventCtx instanceof DocumentEventContext)) {
051            return;
052        }
053        DocumentEventContext docEventCtx = (DocumentEventContext) eventCtx;
054        Task.optionalTask(docEventCtx).ifPresent(task -> handleTask(event, docEventCtx, task));
055    }
056
057    protected void handleTask(Event event, EventContext eventCtx, Task task) {
058        CoreSession session = eventCtx.getCoreSession();
059        List<String> actors = null;
060
061        if (TaskEventNames.WORKFLOW_TASK_ASSIGNED.equals(event.getName())
062                || TaskEventNames.WORKFLOW_TASK_REASSIGNED.equals(event.getName())) {
063            actors = task.getActors();
064        }
065
066        if (TaskEventNames.WORKFLOW_TASK_DELEGATED.equals(event.getName())) {
067            actors = task.getDelegatedActors();
068        }
069        if (actors == null || actors.isEmpty()) {
070            return;
071        }
072        String routeDocId = task.getVariables().get(DocumentRoutingConstants.TASK_ROUTE_INSTANCE_DOCUMENT_ID_KEY);
073        if (routeDocId == null) {
074            return;
075        }
076        DocumentModel routeDoc = session.getDocument(new IdRef(routeDocId));
077        for (String userName : actors) {
078            if (userName.startsWith(NotificationConstants.GROUP_PREFIX)
079                    || userName.startsWith(NotificationConstants.USER_PREFIX)) {
080                // prefixed assignees with "user:" or "group:"
081                userName = userName.substring(userName.indexOf(":") + 1);
082            }
083
084            ACP acp = routeDoc.getACP();
085            ACL routeACL = acp.getOrCreateACL(DocumentRoutingConstants.ROUTE_TASK_LOCAL_ACL);
086            ACE ace = new ACE(userName, SecurityConstants.READ_WRITE, true);
087            if (!routeACL.contains(ace)) {
088                routeACL.add(ace);
089            }
090            acp.addACL(routeACL);
091            session.setACP(routeDoc.getRef(), acp, false);
092        }
093        session.saveDocument(routeDoc);
094    }
095
096    protected DocumentRoutingService getDocumentRoutingService() {
097        return Framework.getService(DocumentRoutingService.class);
098    }
099
100}