001/* 002 * (C) Copyright 2012-2019 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 * ldoguin, Antoine Taillefer 018 * Nuno Cunha (ncunha@nuxeo.com) 019 */ 020package org.nuxeo.ecm.platform.task.core.service; 021 022import java.io.Serializable; 023import java.util.ArrayList; 024import java.util.Date; 025import java.util.HashMap; 026import java.util.List; 027import java.util.Map; 028 029import org.apache.commons.lang3.StringUtils; 030import org.nuxeo.common.utils.Path; 031import org.nuxeo.ecm.core.api.ConcurrentUpdateException; 032import org.nuxeo.ecm.core.api.CoreSession; 033import org.nuxeo.ecm.core.api.DocumentModel; 034import org.nuxeo.ecm.core.api.DocumentNotFoundException; 035import org.nuxeo.ecm.core.api.DocumentRef; 036import org.nuxeo.ecm.core.api.DocumentSecurityException; 037import org.nuxeo.ecm.core.api.IdRef; 038import org.nuxeo.ecm.core.api.NuxeoException; 039import org.nuxeo.ecm.core.api.NuxeoGroup; 040import org.nuxeo.ecm.core.api.NuxeoPrincipal; 041import org.nuxeo.ecm.core.api.PathRef; 042import org.nuxeo.ecm.core.api.SortInfo; 043import org.nuxeo.ecm.core.api.UnrestrictedSessionRunner; 044import org.nuxeo.ecm.core.api.security.ACE; 045import org.nuxeo.ecm.core.api.security.ACL; 046import org.nuxeo.ecm.core.api.security.ACP; 047import org.nuxeo.ecm.core.api.security.SecurityConstants; 048import org.nuxeo.ecm.platform.ec.notification.NotificationConstants; 049import org.nuxeo.ecm.platform.task.Task; 050import org.nuxeo.ecm.platform.task.TaskConstants; 051import org.nuxeo.ecm.platform.task.TaskEventNames; 052import org.nuxeo.ecm.platform.task.TaskPersisterDescriptor; 053import org.nuxeo.ecm.platform.task.TaskProvider; 054import org.nuxeo.ecm.platform.task.TaskProviderDescriptor; 055import org.nuxeo.ecm.platform.task.TaskService; 056import org.nuxeo.runtime.model.ComponentContext; 057import org.nuxeo.runtime.model.ComponentInstance; 058import org.nuxeo.runtime.model.ComponentName; 059import org.nuxeo.runtime.model.DefaultComponent; 060 061/** 062 * @author <a href="mailto:ldoguin@nuxeo.com">Laurent Doguin</a> 063 * @since 5.5 064 */ 065public class TaskServiceImpl extends DefaultComponent implements TaskService { 066 067 private static final long serialVersionUID = 1L; 068 069 public static final ComponentName NAME = new ComponentName("org.nuxeo.ecm.platform.task.core.TaskService"); 070 071 public static final String DEFAULT_TASK_PROVIDER = "documentTaskProvider"; 072 073 private static final String TASK_PROVIDER_XP = "taskProvider"; 074 075 private static final String TASK_PERSISTER_XP = "taskPersister"; 076 077 private Map<String, TaskProvider> tasksProviders; 078 079 private String parentPath = "/task-root"; 080 081 @Override 082 public void activate(ComponentContext context) { 083 super.activate(context); 084 tasksProviders = new HashMap<>(); 085 } 086 087 @Override 088 public void deactivate(ComponentContext context) { 089 super.deactivate(context); 090 tasksProviders = null; 091 } 092 093 @Override 094 public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 095 if (extensionPoint.equals(TASK_PROVIDER_XP)) { 096 if (contribution instanceof TaskProviderDescriptor) { 097 TaskProviderDescriptor taskProviderDescriptor = (TaskProviderDescriptor) contribution; 098 String providerId = taskProviderDescriptor.getId(); 099 if (taskProviderDescriptor.isEnabled()) { 100 tasksProviders.put(providerId, taskProviderDescriptor.getNewInstance()); 101 } else { 102 if (tasksProviders.get(providerId) != null) { 103 tasksProviders.remove(providerId); 104 } 105 } 106 } 107 } else if (extensionPoint.equals(TASK_PERSISTER_XP)) { 108 if (contribution instanceof TaskPersisterDescriptor) { 109 TaskPersisterDescriptor taskPersisterDescriptor = (TaskPersisterDescriptor) contribution; 110 parentPath = taskPersisterDescriptor.getPath(); 111 } 112 } 113 } 114 115 @Override 116 public void unregisterContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 117 if (extensionPoint.equals(TASK_PROVIDER_XP)) { 118 if (contribution instanceof TaskProviderDescriptor) { 119 TaskProviderDescriptor taskProviderDescriptor = (TaskProviderDescriptor) contribution; 120 String providerId = taskProviderDescriptor.getId(); 121 if (tasksProviders.get(providerId) != null) { 122 tasksProviders.remove(providerId); 123 } 124 } 125 } 126 } 127 128 @Override 129 public List<Task> createTask(CoreSession coreSession, NuxeoPrincipal principal, DocumentModel document, 130 String taskName, List<String> actorIds, boolean createOneTaskPerActor, String directive, String comment, 131 Date dueDate, Map<String, String> taskVariables, String parentPath) { 132 return createTask(coreSession, principal, document, taskName, null, null, actorIds, createOneTaskPerActor, 133 directive, comment, dueDate, taskVariables, parentPath); 134 } 135 136 /** 137 * @since 5.6 138 */ 139 @Override 140 public List<Task> createTask(CoreSession coreSession, NuxeoPrincipal principal, DocumentModel document, 141 String taskDocumentType, String taskName, String taskType, String processId, List<String> actorIds, 142 boolean createOneTaskPerActor, String directive, String comment, Date dueDate, 143 Map<String, String> taskVariables, String parentPath, Map<String, Serializable> eventInfo) { 144 List<DocumentModel> docs = new ArrayList<>(); 145 docs.add(document); 146 return createTaskForProcess(coreSession, principal, docs, taskDocumentType, taskName, taskType, processId, null, 147 actorIds, createOneTaskPerActor, directive, comment, dueDate, taskVariables, parentPath, eventInfo); 148 } 149 150 /** 151 * @since 5.6 152 */ 153 @Override 154 public List<Task> createTask(CoreSession coreSession, NuxeoPrincipal principal, DocumentModel document, 155 String taskName, String taskType, String processId, List<String> prefixedActorIds, 156 boolean createOneTaskPerActor, String directive, String comment, Date dueDate, 157 Map<String, String> taskVariables, String parentPath) { 158 return createTask(coreSession, principal, document, TaskConstants.TASK_TYPE_NAME, taskName, taskType, processId, 159 prefixedActorIds, createOneTaskPerActor, directive, comment, dueDate, taskVariables, parentPath, null); 160 } 161 162 @Override 163 public String acceptTask(CoreSession coreSession, NuxeoPrincipal principal, Task task, String comment) { 164 return endTask(coreSession, principal, task, comment, TaskEventNames.WORKFLOW_TASK_COMPLETED, true); 165 } 166 167 @Override 168 public String rejectTask(CoreSession coreSession, NuxeoPrincipal principal, Task task, String comment) { 169 return endTask(coreSession, principal, task, comment, TaskEventNames.WORKFLOW_TASK_REJECTED, false); 170 } 171 172 /** 173 * Use the task provider held by the {@link Task#TASK_PROVIDER_KEY} task variable to end the {@code task}. If null 174 * use the {@link #DEFAULT_TASK_PROVIDER}. 175 */ 176 @Override 177 public String endTask(CoreSession coreSession, NuxeoPrincipal principal, Task task, String comment, 178 String eventName, boolean isValidated) { 179 180 if (!checkPermissions(principal, task)) { 181 throw new DocumentSecurityException( 182 String.format("User with id '%s' cannot end this task", principal.getName())); 183 } else if (!isTaskActive(task)) { 184 throw new ConcurrentUpdateException(String.format("The task '%s' is not active", task.getName())); 185 } 186 String taskProviderId = task.getVariable(Task.TASK_PROVIDER_KEY); 187 if (taskProviderId == null) { 188 taskProviderId = DEFAULT_TASK_PROVIDER; 189 } 190 TaskProvider taskProvider = tasksProviders.get(taskProviderId); 191 if (taskProvider == null) { 192 throw new NuxeoException(String.format( 193 "No task provider registered, cannot end task. Please contribute at least the default task provider: %s.", 194 DEFAULT_TASK_PROVIDER)); 195 } 196 return taskProvider.endTask(coreSession, principal, task, comment, eventName, isValidated); 197 } 198 199 @Override 200 public boolean canEndTask(NuxeoPrincipal principal, Task task) { 201 return isTaskActive(task) && checkPermissions(principal, task); 202 } 203 204 protected boolean checkPermissions(NuxeoPrincipal principal, Task task) { 205 if (task != null && principal != null) { 206 return principal.isAdministrator() || principal.getName().equals(task.getInitiator()) 207 || isTaskAssignedToUser(task, principal, true); 208 } 209 return false; 210 } 211 212 protected boolean isTaskActive(Task task) { 213 if (task != null) { 214 return !task.isCancelled() && !task.hasEnded(); 215 } 216 return false; 217 } 218 219 protected boolean isTaskAssignedToUser(Task task, NuxeoPrincipal user, boolean checkDelegatedActors) { 220 if (task != null && user != null) { 221 // user actors 222 List<String> actors = user.getAllGroups(); 223 actors.add(user.getName()); 224 225 // initiator 226 if (actors.contains(task.getInitiator())) { 227 return true; 228 } 229 // users 230 List<String> users = task.getActors(); 231 if (checkDelegatedActors) { 232 users.addAll(task.getDelegatedActors()); 233 } 234 if (users != null) { 235 for (String userName : users) { 236 if (userName.startsWith(NuxeoPrincipal.PREFIX)) { 237 if (actors.contains(userName.substring(NuxeoPrincipal.PREFIX.length()))) { 238 return true; 239 } 240 } else if (userName.startsWith(NuxeoGroup.PREFIX)) { 241 if (actors.contains(userName.substring(NuxeoGroup.PREFIX.length()))) { 242 return true; 243 } 244 } else if (actors.contains(userName)) { 245 return true; 246 } 247 } 248 } 249 } 250 return false; 251 } 252 253 @Override 254 public Task getTask(CoreSession coreSession, String taskId) { 255 DocumentRef docRef = new IdRef(taskId); 256 DocumentModel taskDoc = coreSession.getDocument(docRef); 257 if (taskDoc != null) { 258 return taskDoc.getAdapter(Task.class); 259 } 260 return null; 261 } 262 263 @Override 264 public void deleteTask(CoreSession coreSession, String taskId) { 265 final DocumentRef docRef = new IdRef(taskId); 266 UnrestrictedSessionRunner runner = new UnrestrictedSessionRunner(coreSession) { 267 @Override 268 public void run() { 269 session.removeDocument(docRef); 270 } 271 }; 272 runner.runUnrestricted(); 273 } 274 275 @Override 276 public DocumentModel getTargetDocumentModel(Task task, CoreSession coreSession) { 277 try { 278 // TODO handle while target documents from task 279 return coreSession.getDocument(new IdRef(task.getTargetDocumentsIds().get(0))); 280 } catch (DocumentNotFoundException e) { 281 return null; 282 } 283 } 284 285 @Override 286 public List<Task> getCurrentTaskInstances(CoreSession coreSession) { 287 List<Task> tasks = new ArrayList<>(); 288 List<Task> newTasks; 289 for (TaskProvider taskProvider : tasksProviders.values()) { 290 newTasks = taskProvider.getCurrentTaskInstances(coreSession); 291 if (newTasks != null) { 292 tasks.addAll(newTasks); 293 } 294 } 295 return tasks; 296 } 297 298 /** 299 * Provide @param sortInfo to handle sort page-provider contributions (see {@link #getCurrentTaskInstances}) 300 * 301 * @since 5.9.3 302 */ 303 @Override 304 public List<Task> getCurrentTaskInstances(CoreSession coreSession, List<SortInfo> sortInfos) { 305 List<Task> tasks = new ArrayList<>(); 306 List<Task> newTasks; 307 for (TaskProvider taskProvider : tasksProviders.values()) { 308 newTasks = taskProvider.getCurrentTaskInstances(coreSession, sortInfos); 309 if (newTasks != null) { 310 tasks.addAll(newTasks); 311 } 312 } 313 return tasks; 314 } 315 316 @Override 317 public List<Task> getAllCurrentTaskInstances(CoreSession coreSession, List<SortInfo> sortInfos) { 318 List<Task> tasks = new ArrayList<>(); 319 List<Task> newTasks; 320 for (TaskProvider taskProvider : tasksProviders.values()) { 321 newTasks = taskProvider.getAllCurrentTaskInstances(coreSession, sortInfos); 322 if (newTasks != null) { 323 tasks.addAll(newTasks); 324 } 325 } 326 return tasks; 327 } 328 329 /** 330 * Returns a list of task instances assigned to one of the actors in the list or to its pool. 331 * 332 * @param actors a list used as actorId to retrieve the tasks. 333 */ 334 @Override 335 public List<Task> getCurrentTaskInstances(List<String> actors, CoreSession coreSession) { 336 List<Task> tasks = new ArrayList<>(); 337 List<Task> newTasks; 338 for (TaskProvider taskProvider : tasksProviders.values()) { 339 newTasks = taskProvider.getCurrentTaskInstances(actors, coreSession); 340 if (newTasks != null) { 341 tasks.addAll(newTasks); 342 } 343 } 344 return tasks; 345 } 346 347 /** 348 * Provide @param sortInfo to handle sort page-provider contributions (see {@link #getCurrentTaskInstances}) 349 * 350 * @since 5.9.3 351 */ 352 @Override 353 public List<Task> getCurrentTaskInstances(List<String> actors, CoreSession coreSession, List<SortInfo> sortInfos) { 354 List<Task> tasks = new ArrayList<>(); 355 List<Task> newTasks; 356 for (TaskProvider taskProvider : tasksProviders.values()) { 357 newTasks = taskProvider.getCurrentTaskInstances(actors, coreSession, sortInfos); 358 if (newTasks != null) { 359 tasks.addAll(newTasks); 360 } 361 } 362 return tasks; 363 } 364 365 @Override 366 public List<Task> getTaskInstances(DocumentModel dm, NuxeoPrincipal user, CoreSession coreSession) { 367 List<Task> tasks = new ArrayList<>(); 368 List<Task> newTasks; 369 for (TaskProvider taskProvider : tasksProviders.values()) { 370 newTasks = taskProvider.getTaskInstances(dm, user, coreSession); 371 if (newTasks != null) { 372 tasks.addAll(newTasks); 373 } 374 } 375 return tasks; 376 } 377 378 @Override 379 public List<Task> getTaskInstances(DocumentModel dm, List<String> actors, CoreSession coreSession) { 380 List<Task> tasks = new ArrayList<>(); 381 List<Task> newTasks; 382 for (TaskProvider taskProvider : tasksProviders.values()) { 383 newTasks = taskProvider.getTaskInstances(dm, actors, coreSession); 384 if (newTasks != null) { 385 tasks.addAll(newTasks); 386 } 387 } 388 return tasks; 389 } 390 391 @Override 392 public List<Task> getAllTaskInstances(String processId, CoreSession session) { 393 List<Task> tasks = new ArrayList<>(); 394 List<Task> newTasks; 395 for (TaskProvider taskProvider : tasksProviders.values()) { 396 newTasks = taskProvider.getAllTaskInstances(processId, session); 397 if (newTasks != null) { 398 tasks.addAll(newTasks); 399 } 400 } 401 return tasks; 402 } 403 404 @Override 405 public List<Task> getAllTaskInstances(String processId, NuxeoPrincipal user, CoreSession session) { 406 List<Task> tasks = new ArrayList<>(); 407 List<Task> newTasks; 408 for (TaskProvider taskProvider : tasksProviders.values()) { 409 newTasks = taskProvider.getAllTaskInstances(processId, user, session); 410 if (newTasks != null) { 411 tasks.addAll(newTasks); 412 } 413 } 414 return tasks; 415 } 416 417 @Override 418 public List<Task> getAllTaskInstances(String processId, List<String> actors, CoreSession session) { 419 List<Task> tasks = new ArrayList<>(); 420 List<Task> newTasks; 421 for (TaskProvider taskProvider : tasksProviders.values()) { 422 newTasks = taskProvider.getAllTaskInstances(processId, actors, session); 423 if (newTasks != null) { 424 tasks.addAll(newTasks); 425 } 426 } 427 return tasks; 428 } 429 430 @Override 431 public String getTaskRootParentPath(CoreSession coreSession) { 432 GetTaskRootParentPathUnrestricted runner = new GetTaskRootParentPathUnrestricted(coreSession); 433 runner.runUnrestricted(); 434 return runner.getParentPath(); 435 } 436 437 public class GetTaskRootParentPathUnrestricted extends UnrestrictedSessionRunner { 438 439 protected DocumentModel taskRootDoc; 440 441 public GetTaskRootParentPathUnrestricted(CoreSession session) { 442 super(session); 443 } 444 445 @Override 446 public void run() { 447 DocumentRef pathRef = new PathRef(parentPath); 448 if (session.exists(pathRef)) { 449 taskRootDoc = session.getDocument(pathRef); 450 } else { 451 Path path = new Path(parentPath); 452 taskRootDoc = session.createDocumentModel(path.removeLastSegments(1).toString(), path.lastSegment(), 453 TaskConstants.TASK_ROOT_TYPE_NAME); 454 taskRootDoc = session.createDocument(taskRootDoc); 455 ACP acp = taskRootDoc.getACP(); 456 ACL acl = acp.getOrCreateACL(ACL.LOCAL_ACL); 457 acl.add(new ACE("Everyone", "Everything", false)); 458 taskRootDoc.setACP(acp, true); 459 taskRootDoc = session.saveDocument(taskRootDoc); 460 } 461 } 462 463 public DocumentModel getTaskRootDoc() { 464 return taskRootDoc; 465 } 466 467 public String getParentPath() { 468 return taskRootDoc.getPathAsString(); 469 } 470 } 471 472 @Override 473 public List<Task> getAllTaskInstances(String processId, String nodeId, CoreSession session) { 474 List<Task> tasks = new ArrayList<>(); 475 List<Task> newTasks; 476 for (TaskProvider taskProvider : tasksProviders.values()) { 477 newTasks = taskProvider.getAllTaskInstances(processId, nodeId, session); 478 if (newTasks != null) { 479 tasks.addAll(newTasks); 480 } 481 } 482 return tasks; 483 } 484 485 @Override 486 public void reassignTask(CoreSession session, final String taskId, final List<String> newActors, 487 final String comment, Map<String, Serializable> eventInfo) { 488 489 new UnrestrictedSessionRunner(session) { 490 491 @Override 492 public void run() { 493 DocumentModel taskDoc = session.getDocument(new IdRef(taskId)); 494 Task task = taskDoc.getAdapter(Task.class); 495 if (task == null) { 496 throw new NuxeoException("Invalid taskId: " + taskId); 497 } 498 List<String> currentAssignees = task.getActors(); 499 List<String> currentActors = new ArrayList<>(); 500 for (String currentAssignee : currentAssignees) { 501 if (currentAssignee.startsWith(NotificationConstants.GROUP_PREFIX) 502 || currentAssignee.startsWith(NotificationConstants.USER_PREFIX)) { 503 // prefixed assignees with "user:" or "group:" 504 currentActors.add(currentAssignee.substring(currentAssignee.indexOf(":") + 1)); 505 } else { 506 currentActors.add(currentAssignee); 507 } 508 } 509 String taskInitator = task.getInitiator(); 510 511 // remove ACLs set for current assignees 512 ACP acp = taskDoc.getACP(); 513 ACL acl = acp.getOrCreateACL(ACL.LOCAL_ACL); 514 List<ACE> toRemove = new ArrayList<>(); 515 516 for (ACE ace : acl.getACEs()) { 517 if (currentActors.contains(ace.getUsername()) || taskInitator.equals(ace.getUsername())) { 518 toRemove.add(ace); 519 } 520 } 521 acl.removeAll(toRemove); 522 523 // grant EVERYTHING on task doc to the new actors 524 List<String> actorIds = new ArrayList<>(); 525 for (String actor : newActors) { 526 if (actor.startsWith(NotificationConstants.GROUP_PREFIX) 527 || actor.startsWith(NotificationConstants.USER_PREFIX)) { 528 // prefixed assignees with "user:" or "group:" 529 actorIds.add(actor.substring(actor.indexOf(":") + 1)); 530 } else { 531 actorIds.add(actor); 532 } 533 } 534 for (String actorId : actorIds) { 535 acl.add(new ACE(actorId, SecurityConstants.EVERYTHING, true)); 536 } 537 538 taskDoc.setACP(acp, true); 539 task.setActors(actorIds); 540 String currentUser = session.getPrincipal().getActingUser(); 541 task.addComment(currentUser, comment); 542 session.saveDocument(taskDoc); 543 544 List<DocumentModel> docs = new ArrayList<>(); 545 for (String string : task.getTargetDocumentsIds()) { 546 docs.add(session.getDocument(new IdRef(string))); 547 548 } 549 notifyEvent(session, task, docs, TaskEventNames.WORKFLOW_TASK_REASSIGNED, eventInfo, comment, 550 session.getPrincipal(), actorIds); 551 552 } 553 }.runUnrestricted(); 554 555 } 556 557 @Override 558 public void delegateTask(CoreSession session, final String taskId, final List<String> delegatedActors, 559 final String comment, Map<String, Serializable> eventInfo) { 560 561 new UnrestrictedSessionRunner(session) { 562 @Override 563 public void run() { 564 DocumentModel taskDoc = session.getDocument(new IdRef(taskId)); 565 Task task = taskDoc.getAdapter(Task.class); 566 if (task == null) { 567 throw new NuxeoException("Invalid taskId: " + taskId); 568 } 569 // grant EVERYTHING on task doc to the delegated actors 570 List<String> actorIds = new ArrayList<>(); 571 ACP acp = taskDoc.getACP(); 572 ACL acl = acp.getOrCreateACL(ACL.LOCAL_ACL); 573 574 for (String actor : delegatedActors) { 575 if (actor.startsWith(NotificationConstants.GROUP_PREFIX) 576 || actor.startsWith(NotificationConstants.USER_PREFIX)) { 577 // prefixed assignees with "user:" or "group:" 578 actorIds.add(actor.substring(actor.indexOf(":") + 1)); 579 } else { 580 actorIds.add(actor); 581 } 582 } 583 for (String actorId : actorIds) { 584 ACE ace = new ACE(actorId, SecurityConstants.EVERYTHING, true); 585 if (!acl.contains(ace)) { 586 acl.add(ace); 587 } 588 } 589 taskDoc.setACP(acp, true); 590 591 List<String> allDelegatedActors = new ArrayList<>(task.getDelegatedActors()); 592 for (String actor : actorIds) { 593 if (!allDelegatedActors.contains(actor)) { 594 allDelegatedActors.add(actor); 595 } 596 } 597 task.setDelegatedActors(allDelegatedActors); 598 599 String currentUser = session.getPrincipal().getActingUser(); 600 task.addComment(currentUser, comment); 601 session.saveDocument(taskDoc); 602 List<DocumentModel> docs = new ArrayList<>(); 603 for (String string : task.getTargetDocumentsIds()) { 604 docs.add(session.getDocument(new IdRef(string))); 605 606 } 607 notifyEvent(session, task, docs, TaskEventNames.WORKFLOW_TASK_DELEGATED, eventInfo, 608 String.format("Task delegated by '%s' to '%s'", currentUser, StringUtils.join(actorIds, ",")) 609 + (!StringUtils.isEmpty(comment) ? " with the following comment: " + comment : ""), 610 session.getPrincipal(), actorIds); 611 } 612 613 }.runUnrestricted(); 614 } 615 616 protected void notifyEvent(CoreSession session, Task task, List<DocumentModel> docs, String event, 617 Map<String, Serializable> eventInfo, String comment, NuxeoPrincipal principal, List<String> actorIds) { 618 Map<String, Serializable> eventProperties = new HashMap<>(); 619 List<String> notificationRecipients = new ArrayList<>(actorIds); 620 eventProperties.put(NotificationConstants.RECIPIENTS_KEY, 621 notificationRecipients.toArray(new String[notificationRecipients.size()])); 622 if (eventInfo != null) { 623 eventProperties.putAll(eventInfo); 624 } 625 for (DocumentModel doc : docs) { 626 TaskEventNotificationHelper.notifyEvent(session, doc, principal, task, event, eventProperties, comment, 627 null); 628 } 629 } 630 631 @Override 632 public List<Task> getTaskInstances(DocumentModel dm, List<String> actors, boolean includeDelegatedTasks, 633 CoreSession session) { 634 List<Task> tasks = new ArrayList<>(); 635 for (TaskProvider taskProvider : tasksProviders.values()) { 636 tasks.addAll(taskProvider.getTaskInstances(dm, actors, includeDelegatedTasks, session)); 637 } 638 return tasks; 639 } 640 641 /** 642 * @since 5.8 643 * @deprecated since 7.4 use 644 * {@link #createTaskForProcess(CoreSession, NuxeoPrincipal, List, String, String, String, String, String, List, boolean, String, String, Date, Map, String, Map)} 645 * instead 646 */ 647 @Override 648 @Deprecated 649 public List<Task> createTask(CoreSession coreSession, NuxeoPrincipal principal, List<DocumentModel> documents, 650 String taskDocumentType, String taskName, String taskType, String processId, List<String> actorIds, 651 boolean createOneTaskPerActor, String directive, String comment, Date dueDate, 652 Map<String, String> taskVariables, String parentPath, Map<String, Serializable> eventInfo) { 653 return createTaskForProcess(coreSession, principal, documents, taskDocumentType, taskName, taskType, processId, 654 null, actorIds, createOneTaskPerActor, directive, comment, dueDate, taskVariables, parentPath, 655 eventInfo); 656 } 657 658 /** 659 * @since 7.4 660 */ 661 @Override 662 public List<Task> createTaskForProcess(CoreSession coreSession, NuxeoPrincipal principal, 663 List<DocumentModel> documents, String taskDocumentType, String taskName, String taskType, String processId, 664 String processName, List<String> actorIds, boolean createOneTaskPerActor, String directive, String comment, 665 Date dueDate, Map<String, String> taskVariables, String parentPath, Map<String, Serializable> eventInfo) { 666 if (StringUtils.isBlank(parentPath)) { 667 parentPath = getTaskRootParentPath(coreSession); 668 } 669 CreateTaskUnrestricted runner = new CreateTaskUnrestricted(coreSession, principal, documents, taskDocumentType, 670 taskName, taskType, processId, processName, actorIds, createOneTaskPerActor, directive, comment, 671 dueDate, taskVariables, parentPath); 672 runner.runUnrestricted(); 673 674 List<Task> tasks = runner.getTasks(); 675 676 for (Task task : tasks) { 677 // notify 678 notifyEvent(coreSession, task, documents, TaskEventNames.WORKFLOW_TASK_ASSIGNED, eventInfo, comment, 679 principal, task.getActors()); 680 } 681 return tasks; 682 } 683}