001/*
002 * (C) Copyright 2012-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.io.Serializable;
021import java.util.ArrayList;
022import java.util.HashMap;
023import java.util.List;
024import java.util.Map;
025
026import org.apache.commons.lang3.StringUtils;
027import org.nuxeo.ecm.core.api.CoreSession;
028import org.nuxeo.ecm.core.api.DocumentModel;
029import org.nuxeo.ecm.core.api.DocumentModelList;
030import org.nuxeo.ecm.core.api.NuxeoException;
031import org.nuxeo.ecm.core.api.NuxeoPrincipal;
032import org.nuxeo.ecm.core.api.SortInfo;
033import org.nuxeo.ecm.platform.query.api.PageProvider;
034import org.nuxeo.ecm.platform.query.api.PageProviderDefinition;
035import org.nuxeo.ecm.platform.query.api.PageProviderService;
036import org.nuxeo.ecm.platform.query.nxql.CoreQueryDocumentPageProvider;
037import org.nuxeo.ecm.platform.task.Task;
038import org.nuxeo.ecm.platform.task.TaskEventNames;
039import org.nuxeo.ecm.platform.task.TaskProvider;
040import org.nuxeo.ecm.platform.task.TaskQueryConstant;
041import org.nuxeo.ecm.platform.task.TaskService;
042import org.nuxeo.ecm.platform.task.core.helpers.TaskActorsHelper;
043import org.nuxeo.runtime.api.Framework;
044
045/**
046 * @author Laurent Doguin
047 * @author Antoine Taillefer
048 * @since 5.5
049 */
050public class DocumentTaskProvider implements TaskProvider {
051
052    private static final long serialVersionUID = 1L;
053
054    @Override
055    public List<Task> getCurrentTaskInstances(CoreSession coreSession) {
056
057        // Get tasks for current user
058        // We need to build the task actors list: prefixed and unprefixed names
059        // of the principal and all its groups
060        NuxeoPrincipal principal = coreSession.getPrincipal();
061        List<String> actors = TaskActorsHelper.getTaskActors(principal);
062
063        return getCurrentTaskInstances(actors, coreSession);
064    }
065
066    /**
067     * Provide @param sortInfo to handle sort page-provider contributions (see {@link #getCurrentTaskInstances})
068     *
069     * @since 5.9.3
070     */
071    @Override
072    public List<Task> getCurrentTaskInstances(CoreSession coreSession, List<SortInfo> sortInfos) {
073
074        // Get tasks for current user
075        // We need to build the task actors list: prefixed and unprefixed names
076        // of the principal and all its groups
077        NuxeoPrincipal principal = coreSession.getPrincipal();
078        List<String> actors = TaskActorsHelper.getTaskActors(principal);
079
080        return getCurrentTaskInstances(actors, coreSession, sortInfos);
081    }
082
083    /**
084     * Returns a list of task instances assigned to one of the actors in the list or to its pool.
085     *
086     * @param actors a list used as actorId to retrieve the tasks.
087     */
088    @Override
089    public List<Task> getCurrentTaskInstances(List<String> actors, CoreSession coreSession) {
090        if (actors == null || actors.isEmpty()) {
091            return new ArrayList<>();
092        }
093        return getTasks(TaskQueryConstant.GET_TASKS_FOR_ACTORS_PP, coreSession, true, null, actors);
094    }
095
096    /**
097     * Provide @param sortInfo to handle sort page-provider contributions (see {@link #getCurrentTaskInstances})
098     *
099     * @since 5.9.3
100     */
101    @Override
102    public List<Task> getCurrentTaskInstances(List<String> actors, CoreSession coreSession, List<SortInfo> sortInfos) {
103        if (actors == null || actors.isEmpty()) {
104            return new ArrayList<>();
105        }
106        return getTasks(TaskQueryConstant.GET_TASKS_FOR_ACTORS_PP, coreSession, true, sortInfos, actors);
107    }
108
109    @Override
110    public List<Task> getTaskInstances(DocumentModel dm, NuxeoPrincipal user, CoreSession coreSession) {
111        if (user == null) {
112            return getTasks(TaskQueryConstant.GET_TASKS_FOR_TARGET_DOCUMENTS_PP, coreSession, true, null, dm.getId(),
113                    dm.getId());
114        } else {
115            List<String> actors = TaskActorsHelper.getTaskActors(user);
116            return getTasks(TaskQueryConstant.GET_TASKS_FOR_TARGET_DOCUMENTS_AND_ACTORS_PP, coreSession, true, null,
117                    dm.getId(), dm.getId(), actors);
118        }
119    }
120
121    @Override
122    public List<Task> getTaskInstances(DocumentModel dm, List<String> actors, CoreSession coreSession) {
123        if (actors == null || actors.isEmpty()) {
124            return new ArrayList<>();
125        }
126        return getTasks(TaskQueryConstant.GET_TASKS_FOR_TARGET_DOCUMENTS_AND_ACTORS_PP, coreSession, true, null,
127                dm.getId(), dm.getId(), actors);
128    }
129
130    @Override
131    public List<Task> getAllTaskInstances(String processId, CoreSession session) {
132        return getTasks(TaskQueryConstant.GET_TASKS_FOR_PROCESS_PP, session, true, null, processId);
133    }
134
135    @Override
136    public List<Task> getAllTaskInstances(String processId, NuxeoPrincipal user, CoreSession session) {
137        List<String> actors = TaskActorsHelper.getTaskActors(user);
138        return getAllTaskInstances(processId, actors, session);
139    }
140
141    @Override
142    public List<Task> getAllTaskInstances(String processId, List<String> actors, CoreSession session) {
143        return getTasks(TaskQueryConstant.GET_TASKS_FOR_PROCESS_AND_ACTORS_PP, session, true, null, processId, actors);
144    }
145
146    /**
147     * Converts a {@link DocumentModelList} to a list of {@link Task}s.
148     *
149     * @since 6.0
150     */
151    public static List<Task> wrapDocModelInTask(List<DocumentModel> taskDocuments) {
152        List<Task> tasks = new ArrayList<>();
153        for (DocumentModel doc : taskDocuments) {
154            tasks.add(doc.getAdapter(Task.class));
155        }
156        return tasks;
157    }
158
159    /**
160     * @deprecated since 6.0, use {@link #wrapDocModelInTask(List)} instead.
161     */
162    @Deprecated
163    public static List<Task> wrapDocModelInTask(DocumentModelList taskDocuments) {
164        return wrapDocModelInTask(taskDocuments, false);
165    }
166
167    /**
168     * Converts a {@link DocumentModelList} to a list of {@link Task}s.
169     *
170     * @param detach if {@code true}, detach each document before converting it to a {@code Task}.
171     * @deprecated since 6.0, use {@link #wrapDocModelInTask(List)} instead.
172     */
173    @Deprecated
174    public static List<Task> wrapDocModelInTask(DocumentModelList taskDocuments, boolean detach) {
175        List<Task> tasks = new ArrayList<>();
176        for (DocumentModel doc : taskDocuments) {
177            if (detach) {
178                doc.detach(true);
179            }
180            tasks.add(doc.getAdapter(Task.class));
181        }
182        return tasks;
183    }
184
185    @Override
186    public String endTask(CoreSession coreSession, NuxeoPrincipal principal, Task task, String comment,
187            String eventName, boolean isValidated) {
188
189        // put user comment on the task
190        if (!StringUtils.isEmpty(comment)) {
191            task.addComment(principal.getName(), comment);
192        }
193
194        // end the task, adding boolean marker that task was validated or
195        // rejected
196        task.setVariable(TaskService.VariableName.validated.name(), String.valueOf(isValidated));
197        task.end(coreSession);
198        // make sure taskDoc is attached to prevent sending event with null session
199        DocumentModel taskDocument = task.getDocument();
200        if (!taskDocument.isAttached()) {
201            taskDocument.attach(coreSession);
202        }
203        coreSession.saveDocument(taskDocument);
204        if (StringUtils.isNotBlank(eventName)) {
205            TaskEventNotificationHelper.notifyTaskEnded(coreSession, principal, task, comment, eventName, null);
206        }
207        return isValidated ? TaskEventNames.WORKFLOW_TASK_COMPLETED : TaskEventNames.WORKFLOW_TASK_REJECTED;
208    }
209
210    @Override
211    public List<Task> getAllTaskInstances(String processId, String nodeId, CoreSession session) {
212        return getTasks(TaskQueryConstant.GET_TASKS_FOR_PROCESS_AND_NODE_PP, session, true, null, processId, nodeId);
213    }
214
215    @Override
216    public List<Task> getTaskInstances(DocumentModel dm, List<String> actors, boolean includeDelegatedTasks,
217            CoreSession session) {
218        if (includeDelegatedTasks) {
219            return getTasks(TaskQueryConstant.GET_TASKS_FOR_TARGET_DOCUMENTS_AND_ACTORS_OR_DELEGATED_ACTORS_PP, session,
220                    true, null, dm.getId(), dm.getId(), actors, actors);
221        } else {
222            return getTasks(TaskQueryConstant.GET_TASKS_FOR_TARGET_DOCUMENTS_AND_ACTORS_PP, session, true, null,
223                    dm.getId(), dm.getId(), actors);
224        }
225    }
226
227    @Override
228    public List<Task> getAllCurrentTaskInstances(CoreSession session, List<SortInfo> sortInfos) {
229        // Get tasks for current user
230        // We need to build the task actors list: prefixed and unprefixed names
231        // of the principal and all its groups
232        NuxeoPrincipal principal = session.getPrincipal();
233        List<String> actors = TaskActorsHelper.getTaskActors(principal);
234
235        return getTasks(TaskQueryConstant.GET_TASKS_FOR_ACTORS_OR_DELEGATED_ACTORS_PP, session, true, sortInfos, actors,
236                actors);
237    }
238
239    /**
240     * @since 6.0
241     */
242    @SuppressWarnings("unchecked")
243    public static List<Task> getTasks(String pageProviderName, CoreSession session, boolean unrestricted,
244            List<SortInfo> sortInfos, Object... params) {
245        PageProviderService ppService = Framework.getService(PageProviderService.class);
246        if (ppService == null) {
247            throw new RuntimeException("Missing PageProvider service");
248        }
249        Map<String, Serializable> props = new HashMap<>();
250        // first retrieve potential props from definition
251        PageProviderDefinition def = ppService.getPageProviderDefinition(pageProviderName);
252        if (def != null) {
253            Map<String, String> defProps = def.getProperties();
254            if (defProps != null) {
255                props.putAll(defProps);
256            }
257        }
258        props.put(CoreQueryDocumentPageProvider.CORE_SESSION_PROPERTY, (Serializable) session);
259        if (unrestricted) {
260            props.put(CoreQueryDocumentPageProvider.USE_UNRESTRICTED_SESSION_PROPERTY, Boolean.TRUE);
261        }
262        PageProvider<DocumentModel> pp = (PageProvider<DocumentModel>) ppService.getPageProvider(pageProviderName,
263                sortInfos, null, null, props, params);
264        if (pp == null) {
265            throw new NuxeoException("Page provider not found: " + pageProviderName);
266        }
267        return wrapDocModelInTask(pp.getCurrentPage());
268    }
269
270}