001/*
002 * (C) Copyright 2011 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 */
016package org.nuxeo.ecm.platform.task.core.service;
017
018import java.util.ArrayList;
019import java.util.Collections;
020import java.util.Date;
021import java.util.HashMap;
022import java.util.List;
023import java.util.Map;
024
025import org.apache.commons.lang.StringUtils;
026import org.nuxeo.ecm.core.api.CoreSession;
027import org.nuxeo.ecm.core.api.DocumentModel;
028import org.nuxeo.ecm.core.api.NuxeoException;
029import org.nuxeo.ecm.core.api.NuxeoPrincipal;
030import org.nuxeo.ecm.core.api.UnrestrictedSessionRunner;
031import org.nuxeo.ecm.core.api.security.ACE;
032import org.nuxeo.ecm.core.api.security.ACL;
033import org.nuxeo.ecm.core.api.security.ACP;
034import org.nuxeo.ecm.core.api.security.SecurityConstants;
035import org.nuxeo.ecm.platform.ec.notification.NotificationConstants;
036import org.nuxeo.ecm.platform.task.Task;
037import org.nuxeo.ecm.platform.task.TaskConstants;
038import org.nuxeo.ecm.platform.task.TaskService;
039
040/**
041 * @since 5.5
042 */
043public class CreateTaskUnrestricted extends UnrestrictedSessionRunner {
044
045    private NuxeoPrincipal principal;
046
047    private DocumentModel document;
048
049    private String taskName;
050
051    /**
052     * @since 5.6
053     */
054    private String taskType;
055
056    /**
057     * @since 5.6
058     */
059    private String processId;
060
061    /**
062     * @since 5.6
063     */
064    private String taskDocumentType;
065
066    private List<String> prefixedActorIds;
067
068    private boolean createOneTaskPerActor;
069
070    private String directive;
071
072    private String comment;
073
074    private Date dueDate;
075
076    private Map<String, String> taskVariables;
077
078    private String parentPath;
079
080    /**
081     * @since 7.4
082     */
083    private String processName;
084
085    List<Task> tasks = new ArrayList<Task>();
086
087    /**
088     * @since 5.8 A task can have many target documents
089     */
090    protected List<DocumentModel> documents;
091
092    public CreateTaskUnrestricted(CoreSession session, NuxeoPrincipal principal, DocumentModel document,
093            String taskName, List<String> prefixedActorIds, boolean createOneTaskPerActor, String directive,
094            String comment, Date dueDate, Map<String, String> taskVariables, String parentPath) {
095        this(session, principal, document, taskName, null, null, prefixedActorIds, createOneTaskPerActor, directive,
096                comment, dueDate, taskVariables, parentPath);
097    }
098
099    /**
100     * @since 5.6
101     */
102    public CreateTaskUnrestricted(CoreSession session, NuxeoPrincipal principal, DocumentModel document,
103            String taskName, String taskType, String processId, List<String> prefixedActorIds,
104            boolean createOneTaskPerActor, String directive, String comment, Date dueDate,
105            Map<String, String> taskVariables, String parentPath) {
106        super(session);
107        this.principal = principal;
108        this.document = document;
109        this.taskName = taskName;
110        this.taskType = taskType;
111        this.processId = processId;
112        this.prefixedActorIds = prefixedActorIds;
113        this.createOneTaskPerActor = createOneTaskPerActor;
114        this.directive = directive;
115        this.comment = comment;
116        this.dueDate = dueDate;
117        this.taskVariables = taskVariables;
118        this.parentPath = parentPath;
119        documents = new ArrayList<DocumentModel>();
120        documents.add(document);
121    }
122
123    /**
124     * @since 5.6
125     */
126    public CreateTaskUnrestricted(CoreSession session, NuxeoPrincipal principal, DocumentModel document,
127            String taskDocumentType, String taskName, String taskType, String processId, List<String> prefixedActorIds,
128            boolean createOneTaskPerActor, String directive, String comment, Date dueDate,
129            Map<String, String> taskVariables, String parentPath) {
130        this(session, principal, document, taskName, taskType, processId, prefixedActorIds, createOneTaskPerActor,
131                directive, comment, dueDate, taskVariables, parentPath);
132        this.taskDocumentType = taskDocumentType;
133    }
134
135    /**
136     * @since 5.8
137     */
138    public CreateTaskUnrestricted(CoreSession session, NuxeoPrincipal principal, List<DocumentModel> documents,
139            String taskDocumentType, String taskName, String taskType, String processId, List<String> prefixedActorIds,
140            boolean createOneTaskPerActor, String directive, String comment, Date dueDate,
141            Map<String, String> taskVariables, String parentPath) {
142        this(session, principal, documents != null && documents.size() > 0 ? documents.get(0) : null, taskName,
143                taskType, processId, prefixedActorIds, createOneTaskPerActor, directive, comment, dueDate,
144                taskVariables, parentPath);
145        this.taskDocumentType = taskDocumentType;
146        this.documents = documents;
147        if (this.documents != null && this.documents.size() > 0) {
148            document = documents.get(0);
149        }
150    }
151
152    /**
153     * @since 7.4
154     */
155    public CreateTaskUnrestricted(CoreSession session, NuxeoPrincipal principal, List<DocumentModel> documents,
156            String taskDocumentType, String taskName, String taskType, String processId, String processName,
157            List<String> prefixedActorIds, boolean createOneTaskPerActor, String directive, String comment,
158            Date dueDate, Map<String, String> taskVariables, String parentPath) {
159        this(session, principal, documents != null && documents.size() > 0 ? documents.get(0) : null, taskName,
160                taskType, processId, prefixedActorIds, createOneTaskPerActor, directive, comment, dueDate,
161                taskVariables, parentPath);
162        this.taskDocumentType = taskDocumentType;
163        this.documents = documents;
164        this.processName = processName;
165        if (this.documents != null && this.documents.size() > 0) {
166            document = documents.get(0);
167        }
168    }
169
170    @Override
171    public void run() {
172        if (StringUtils.isEmpty(taskDocumentType)) {
173            taskDocumentType = TaskConstants.TASK_TYPE_NAME;
174        }
175        createTask(session, principal, documents, taskDocumentType, taskName, taskType, processId, processName,
176                prefixedActorIds, createOneTaskPerActor, directive, comment, dueDate, taskVariables, parentPath);
177    }
178
179    /**
180     * @since 5.6
181     */
182    public void createTask(CoreSession coreSession, NuxeoPrincipal principal, DocumentModel document,
183            String taskDocumentType, String taskName, String taskType, String processId, List<String> prefixedActorIds,
184            boolean createOneTaskPerActor, String directive, String comment, Date dueDate,
185            Map<String, String> taskVariables, String parentPath) {
186        List<DocumentModel> docs = new ArrayList<DocumentModel>();
187        docs.add(document);
188        createTask(coreSession, principal, docs, taskDocumentType, taskName, taskType, processId, prefixedActorIds,
189                createOneTaskPerActor, directive, comment, dueDate, taskVariables, parentPath);
190
191    }
192
193    /**
194     * @since 5.8
195     */
196    public void createTask(CoreSession coreSession, NuxeoPrincipal principal, List<DocumentModel> documents,
197            String taskDocumentType, String taskName, String taskType, String processId, List<String> prefixedActorIds,
198            boolean createOneTaskPerActor, String directive, String comment, Date dueDate,
199            Map<String, String> taskVariables, String parentPath) {
200        createTask(coreSession, principal, documents, taskDocumentType, taskName, taskType, processId, null,
201                prefixedActorIds, createOneTaskPerActor, directive, comment, dueDate, taskVariables, parentPath);
202    }
203
204    /**
205     * @since 7.4
206     */
207    public void createTask(CoreSession coreSession, NuxeoPrincipal principal, List<DocumentModel> documents,
208            String taskDocumentType, String taskName, String taskType, String processId, String processName,
209            List<String> prefixedActorIds, boolean createOneTaskPerActor, String directive, String comment,
210            Date dueDate, Map<String, String> taskVariables, String parentPath) {
211        if (createOneTaskPerActor) {
212            for (String prefixedActorId : prefixedActorIds) {
213                createTask(coreSession, principal, documents, taskDocumentType, taskName, taskType, processId,
214                        Collections.singletonList(prefixedActorId), false, directive, comment, dueDate, taskVariables,
215                        parentPath);
216            }
217        } else {
218            // use task type as a docName (is actually the nodeId so it
219            // doesn't contain "/" characters), but fallback on task name
220            // if task type is null (for old API kept for compat)
221            String docName = taskType == null ? taskName : taskType;
222            DocumentModel taskDocument = session.createDocumentModel(parentPath, docName, taskDocumentType);
223            Task task = taskDocument.getAdapter(Task.class);
224            if (task == null) {
225                throw new NuxeoException("Document " + taskDocumentType + "  can not be adapted to a Task");
226            }
227            task.setName(taskName);
228            task.setType(taskType);
229            task.setProcessId(processId);
230            task.setProcessName(processName);
231            task.setCreated(new Date());
232            if (principal != null) {
233                String username = principal.getActingUser();
234                task.setInitiator(username);
235            }
236            task.setActors(prefixedActorIds);
237            task.setDueDate(dueDate);
238
239            if (documents != null) {
240                List<String> docIds = new ArrayList<String>();
241                for (DocumentModel doc : documents) {
242                    docIds.add(doc.getId());
243                }
244                task.setTargetDocumentsIds(docIds);
245            }
246            task.setDirective(directive);
247
248            if (!StringUtils.isEmpty(comment)) {
249                task.addComment(principal.getName(), comment);
250            }
251
252            // add variables
253            Map<String, String> variables = new HashMap<String, String>();
254            if (document != null) {
255                variables.put(TaskService.VariableName.documentId.name(), document.getId());
256                variables.put(TaskService.VariableName.documentRepositoryName.name(), document.getRepositoryName());
257            }
258            variables.put(TaskService.VariableName.directive.name(), directive);
259            variables.put(TaskService.VariableName.createdFromTaskService.name(), "true");
260            if (taskVariables != null) {
261                variables.putAll(taskVariables);
262            }
263            task.setVariables(variables);
264
265            // create document in order to set its ACP
266            taskDocument = session.createDocument(taskDocument);
267
268            // re-fetch task from task document to set its id
269            task = taskDocument.getAdapter(Task.class);
270
271            // Set rights
272            List<String> actorIds = new ArrayList<String>();
273            for (String actor : prefixedActorIds) {
274                if (actor.startsWith(NotificationConstants.GROUP_PREFIX)
275                        || actor.startsWith(NotificationConstants.USER_PREFIX)) {
276                    // prefixed assignees with "user:" or "group:"
277                    actorIds.add(actor.substring(actor.indexOf(":") + 1));
278                } else {
279                    actorIds.add(actor);
280                }
281            }
282            ACP acp = taskDocument.getACP();
283            ACL acl = acp.getOrCreateACL(ACL.LOCAL_ACL);
284            if (principal != null) {
285                acl.add(new ACE(principal.getName(), SecurityConstants.EVERYTHING, true));
286
287            }
288            for (String actorId : actorIds) {
289                acl.add(new ACE(actorId, SecurityConstants.EVERYTHING, true));
290            }
291            acp.addACL(acl);
292            taskDocument.setACP(acp, true);
293            taskDocument = session.saveDocument(taskDocument);
294            tasks.add(taskDocument.getAdapter(Task.class));
295        }
296    }
297
298    public void createTask(CoreSession coreSession, NuxeoPrincipal principal, DocumentModel document, String taskName,
299            List<String> prefixedActorIds, boolean createOneTaskPerActor, String directive, String comment,
300            Date dueDate, Map<String, String> taskVariables, String parentPath) {
301        createTask(coreSession, principal, document, TaskConstants.TASK_TYPE_NAME, taskName, null, null,
302                prefixedActorIds, createOneTaskPerActor, directive, comment, dueDate, taskVariables, parentPath);
303    }
304
305    public List<Task> getTasks() {
306        return tasks;
307    }
308
309}