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