PluginProbe
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration / 2.2.0
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration v2.2.0
2.2.1 2.2.0 2.1.0 2.0.15 2.0.12 2.0.10 2.0.4 2.0.1 2.0.0 1.95.3 1.95.2 1.95 1.91.6 trunk 1.11 1.12 1.13 1.20 1.21 1.22 1.23 1.30 1.31 1.32 1.35 All 44 releases
← All changes | app/Services/StageService.php +58 -1 2.0.0 → 2.2.0 View file →
@@ -508,14 +508,26 @@
508 508
509 509 public function moveAllTasks($oldStageId, $newStageId)
510 510 {
511 511 $tasks = Task::where('stage_id', $oldStageId)->whereNull('parent_id')->whereNull('archived_at')->get();
512 + $sourceStage = Stage::findOrFail($oldStageId);
513 + $targetStage = Stage::findOrFail($newStageId);
512 514
515 + // Reuse task-user relations unless default assignments change them.
516 + $tasks->load(['assignees', 'watchers']);
517 +
513 518 // get the last position available of that stage
514 - $position = (new TaskService())->getLastPositionOfTasks($newStageId);
519 + $taskService = new TaskService();
520 + $position = $taskService->getLastPositionOfTasks($newStageId);
521 + $notificationService = new NotificationService();
522 + $currentUserId = get_current_user_id();
523 + // Stage-email eligibility per watcher, resolved in batches and shared across tasks.
524 + $emailEligibility = [];
515 525
516 526 // update tasks stage and position
517 527 foreach ($tasks as $key => $task) {
528 + $taskOldStageId = $task->stage_id;
529 +
518 530 // Clean up archived_by_stage meta when moving to different stage
519 531 TaskMeta::where('task_id', $task->id)
520 532 ->where('key', Constant::META_KEY_ARCHIVED_BY_STAGE)
521 533 ->delete();
@@ -521,10 +533,55 @@
521 533 ->delete();
522 534
523 535 $task->stage_id = $newStageId;
524 536 $task->position = $position + $key;
537 + $task->setRelation('stage', $targetStage);
525 538 $task->save();
539 +
540 + if ((int) $taskOldStageId !== (int) $newStageId) {
541 + $assignmentsChanged = $taskService->manageDefaultAssignees($task, $newStageId, $targetStage);
542 + if ($targetStage->defaultTaskStatus() === 'closed' && $task->status !== 'closed') {
543 + $task = $task->close();
544 + }
545 + // Assignment hooks may change assignees and watchers before notification.
546 + if ($assignmentsChanged) {
547 + $task->load(['assignees', 'watchers']);
548 + }
549 +
550 + do_action('fluent_boards/task_stage_updated', $task, $taskOldStageId, [
551 + 'source' => $sourceStage,
552 + 'target' => $targetStage,
553 + ]);
554 +
555 + $watcherIds = array_diff(array_map('intval', $task->watchers->pluck('ID')->toArray()), [$currentUserId]);
556 + $unknownIds = array_diff($watcherIds, array_keys($emailEligibility));
557 + if ($unknownIds) {
558 + $emailEligibility += array_fill_keys($unknownIds, false);
559 + $enabledIds = $notificationService->getEmailEnabledUserIds($task->board_id, $unknownIds, Constant::BOARD_EMAIL_STAGE_CHANGE);
560 + foreach ($enabledIds as $enabledId) {
561 + $emailEligibility[$enabledId] = true;
562 + }
563 + }
564 + $recipients = [];
565 + foreach ($task->watchers as $watcher) {
566 + if (!empty($emailEligibility[(int) $watcher->ID])) {
567 + $recipients[] = $watcher->user_email;
568 + }
569 + }
570 + $taskService->sendMailAfterTaskModify('stage_change', $recipients, $task->id);
571 + }
526 572 }
573 +
574 + if ($tasks->count() && (int) $sourceStage->id !== (int) $targetStage->id) {
575 + do_action(
576 + 'fluent_boards/tasks_moved_between_stages',
577 + $sourceStage->board_id,
578 + $sourceStage,
579 + $targetStage,
580 + $tasks->count()
581 + );
582 + }
583 +
527 584 return $tasks;
528 585 }
529 586 public function archiveAllTasksInStage($stage_id, $boardId = null)
530 587 {