PluginProbe
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration / 1.35
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration v1.35
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 1.40 1.41 1.45 All 41 releases
fluent-boards / app / Services / StageService.php

StageService.php in FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration 1.35, at app/Services/StageService.php

450 lines 14.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentBoards\App\Services;
4
5 use FluentBoards\App\Models\Task;
6 use FluentBoards\App\Models\Board;
7 use FluentBoards\App\Models\Stage;
8 use FluentBoards\Framework\Http\Request\Request;
9 use FluentBoards\Framework\Support\Arr;
10
11 class StageService
12 {
13 public function createDefaultStages($board)
14 {
15 $stages = $this->defaultStages($board);
16 foreach ($stages as $stage) {
17 Stage::create($stage);
18 }
19 }
20
21 public function defaultStages($board)
22 {
23 return $this->defaultStagesForTodos($board->id);
24 }
25
26 public function defaultStagesForTodos($boardId)
27 {
28 return [
29 [
30 'board_id' => $boardId,
31 'title' => 'Open',
32 'position' => 1,
33 'slug' => 'open',
34 'settings' => [
35 'default_task_status' => 'open'
36 ]
37 ],
38 [
39 'board_id' => $boardId,
40 'title' => 'In Progress',
41 'position' => 2,
42 'slug' => 'in-progress',
43 'settings' => [
44 'default_task_status' => 'open'
45 ]
46 ],
47 [
48 'board_id' => $boardId,
49 'title' => 'Completed',
50 'position' => 3,
51 'slug' => 'completed',
52 'settings' => [
53 'default_task_status' => 'closed'
54 ]
55 ]
56 ];
57 }
58 public function updateStageProperty($col, $value, $stageId)
59 {
60 $stage = Stage::findOrFail($stageId);
61
62 if ('title' == $col) {
63 $stage = $this->updateTitle($value, $stage);
64 } elseif ('status' == $col) {
65 $stage = $this->updateStatus($value, $stage);
66 } elseif ('color' == $col) {
67 $stage = $this->updateColor($value, $stage);
68 } elseif ('bg_color' == $col) {
69 $stage = $this->updateBackgroundColor($value, $stage);
70 } elseif ('archived_at' == $col) {
71 $stage = $this->updateArchivedAt($value, $stage);
72 }
73 return $stage;
74 }
75
76 public function getLastOneMinuteUpdatedStages($boardId)
77 {
78 $oneMinuteAgoTimestamp = current_time('timestamp') - 60;
79 return Stage::where('board_id', $boardId)
80 ->where('updated_at', '>=', date_i18n('Y-m-d H:i:s', $oneMinuteAgoTimestamp))
81 ->get();
82 }
83
84 private function updateTitle($value, $stage)
85 {
86 $stage->title = $value;
87 $stage->save();
88 return $stage;
89 }
90
91 private function updateStatus($value, $stage)
92 {
93 $oldSettings = $stage->settings;
94 $oldSettings['default_task_status'] = $value;
95 $stage->settings = $oldSettings;
96 $stage->save();
97 return $stage;
98 }
99
100 private function updateColor($value, $stage)
101 {
102 $stage->color = $value;
103 $stage->save();
104 return $stage;
105 }
106
107 private function updateBackgroundColor($value, $stage)
108 {
109 $stage->bg_color = $value;
110 $stage->save();
111 return $stage;
112 }
113
114 private function updateArchivedAt($value, $stage)
115 {
116 $stage->archived_at = $value;
117 $stage->save();
118 return $stage;
119 }
120
121 public function createStage($stageData, $boardId)
122 {
123 $stage = new Stage();
124 $stage->board_id = $boardId;
125 $stage->title = $stageData['title'];
126 $stage->settings = [
127 'default_task_status' => Arr::get($stageData, 'status') ?? 'open',
128 'default_task_assignees' => []
129 ];
130 if (!Arr::get($stageData, 'position')) {
131 $lastStagePosition = $this->getLastPositionOfStagesOfBoard($boardId);
132 $stage->position = $lastStagePosition ? $lastStagePosition->position + 1 : 1;
133 $stage->save();
134 } else {
135 $stage->position = (int)$stageData['position'];
136 $stage->save();
137 $this->moveOtherStages($stage);
138 }
139
140 return $stage;
141 }
142
143 public function getLastPositionOfStagesOfBoard($boardId)
144 {
145 // return last position of stages of board
146 return Stage::where('board_id', $boardId)
147 ->whereNull('archived_at')
148 ->orderBy('position', 'desc')
149 ->first();
150 }
151
152 protected function moveOtherStages($stage)
153 {
154
155 $stages = Stage::where('board_id', $stage->board_id)
156 ->where('position', '>=', $stage->position)
157 ->whereNotIn('id', [$stage->id])
158 ->whereNull('archived_at')->get();
159
160 foreach ($stages as $stage) {
161 $stage->position = $stage->position + 1;
162 $stage->save();
163 }
164 }
165
166 public function copyStagesOfBoard($board, $fromBoardId)
167 {
168 $stages = Stage::where('board_id', $fromBoardId)->where('type', 'stage')->whereNull('archived_at')->get();
169 $stageMapForCopyingTask = array();
170 foreach($stages as $key => $stage)
171 {
172 $stageToSave = array();
173 $stageToSave['title'] = $stage['title'];
174 $stageToSave['board_id'] = $board->id;
175 $stageToSave['slug'] = str_replace(' ', '-', strtolower($stage['title']));
176 $stageToSave['type'] = 'stage';
177 $stageToSave['position'] = $key + 1;
178 $stageToSave['settings'] = [
179 'default_task_status' => $stage->settings['default_task_status']
180 ];
181 $newStage = Stage::create($stageToSave);
182 $stageMapForCopyingTask[$stage['id']] = $newStage->id;
183 }
184 return $stageMapForCopyingTask;
185 }
186
187 public function importStagesFromBoard($board_id, $selectedStages)
188 {
189 $targetStages = Stage::whereIn('id', $selectedStages)->get();
190 $stageMapForCopyingTask = array();
191 $stageIdsToCopy = array();
192
193 //need to define position of stage
194 $numberOfStages = Stage::where('board_id', $board_id)->whereNull('archived_at')->count();
195
196 foreach($targetStages as $key => $stage)
197 {
198 $stageToSave = array();
199 $stageToSave['title'] = $stage['title'] . ' - imported';
200 $stageToSave['board_id'] = $board_id;
201 $stageToSave['slug'] = str_replace(' ', '-', strtolower($stage['title']));
202 $stageToSave['type'] = 'stage';
203 $stageToSave['position'] = $numberOfStages + $key + 1;
204 $stageToSave['settings'] = [
205 'default_task_status' => $stage->settings['default_task_status']
206 ];
207 $newStage = Stage::create($stageToSave);
208 $stageMapForCopyingTask[$stage['id']] = $newStage->id;
209 $stageIdsToCopy[] = $stage['id'];
210 }
211
212 $this->importTasks($board_id, $stageMapForCopyingTask, $stageIdsToCopy);
213 }
214
215 public function importTasks($boardId, $stageMapper, $stageIds)
216 {
217 $tasksToImport = Task::whereIn('stage_id', $stageIds)->whereNull('archived_at')->get();
218
219 foreach($tasksToImport as $task)
220 {
221 $newTask = array();
222 $newTask['title'] = $task->title;
223 $newTask['description'] = $task->description;
224 $newTask['board_id'] = $boardId;
225 $newTask['stage_id'] = $stageMapper[$task->stage_id];
226 $newTask['status'] = $task->status;
227 $newTask['priority'] = $task->priority;
228 $newTask['position'] = $task->position;
229 $newTask['due_at'] = $task->due_at;
230 Task::create($newTask);
231 }
232
233 //update task count of board
234 $totalTasks = sizeof($tasksToImport);
235 $board = Board::findOrFail($boardId);
236 $settings = $board->settings ?? [];
237
238 if (isset($settings['tasks_count'])) {
239 $settings['tasks_count'] += $totalTasks;
240 } else {
241 $settings['tasks_count'] = $totalTasks;
242 }
243 $board->settings = $settings;
244 $board->save();
245 }
246
247 public function updateStageTemplate($stage_id)
248 {
249 $stage = Stage::findOrFail($stage_id);
250 $stageSettings = $stage->settings;
251 if($stageSettings && array_key_exists('is_template', $stageSettings))
252 {
253 $currentlyIsTemplate = $stageSettings['is_template'];
254 if($currentlyIsTemplate){
255 $stageSettings['is_template'] = false;
256 $stage->settings = $stageSettings;
257 }else{
258 $stageSettings['is_template'] = true;
259 $stage->settings = $stageSettings;
260 }
261 }else {
262 if(!$stageSettings) {
263 $stage->settings = [
264 'is_template' => true
265 ];
266 } else {
267 $stage->settings = array_merge($stage->settings, [
268 'is_template' => true
269 ]);
270 }
271
272 }
273 $stage->save();
274
275 return $stage;
276 }
277
278 public function moveAllTasks($oldStageId, $newStageId)
279 {
280 $tasks = Task::where('stage_id', $oldStageId)->whereNull('parent_id')->whereNull('archived_at')->get();
281
282 // get the last position available of that stage
283 $position = (new TaskService())->getLastPositionOfTasks($newStageId);
284
285 // update tasks stage and position
286 foreach ($tasks as $key => $task) {
287 $task->stage_id = $newStageId;
288 $task->position = $position + $key;
289 $task->save();
290 }
291 return $tasks;
292 }
293 public function archiveAllTasksInStage($stage_id)
294 {
295 $tasks = Task::where('stage_id', $stage_id)->whereNull('parent_id')->whereNull('archived_at')->get();
296 foreach ($tasks as $task) {
297 $task->position = 0;
298 $task->archived_at = current_time('mysql');
299 $task->save();
300 do_action('fluent_boards/task_archived', $task);
301 }
302 return $tasks;
303 }
304
305 public function createRoadmapStages($board, $stagesData)
306 {
307 foreach ($stagesData as $index => $formStageData) {
308 $stage = new Stage();
309 $stage->board_id = $board->id;
310 $stage->title = $formStageData['title'];
311 $stage->slug = $formStageData['slug'];
312 $stage->position = $formStageData['position'] ? $formStageData['position'] : 1;
313 $stage->settings = $this->roadmapStageSetting($index);
314 $stage->save();
315 }
316 return $stagesData;
317 }
318
319 /*
320 * I have no idea what this function does, but I am doing it
321 * to make the code work
322 */
323 public function roadmapStageSetting($index)
324 {
325 return [
326 'is_public' => $index > 0 ? true : false,
327 'default_task_status' => 'open',
328 'is_template' => false,
329 ];
330 }
331
332
333 public function createStages($board, $stageData)
334 {
335 $firstStage = null;
336 foreach ($stageData as $index => $stage) {
337 $stageToPush = array();
338 $stageToPush['title'] = $stage['title'];
339 $stageToPush['board_id'] = $board->id;
340 $stageToPush['position'] = $index + 1;
341 $stageToPush['slug'] = $this->createSlug($stage['title']);
342
343 if (Arr::get($stage, 'title') == 'Completed') {
344 $stageToPush['settings'] = [
345 'default_task_status' => 'closed',
346 'is_template' => false
347 ];
348 }
349
350 $stage = Stage::create($stageToPush);
351 if($index == 0){
352 $firstStage = $stage;
353 }
354 }
355 return $firstStage;
356 }
357
358 private function createSlug($title)
359 {
360 return str_replace(' ', '-', strtolower($title));
361 }
362
363 public function stagesByBoardId($boardId)
364 {
365 return Stage::where('board_id', $boardId)->whereNull('archived_at')->get();
366 }
367
368
369
370 public function sortStageTasks($order, $orderBy, $stage_id)
371 {
372 $sortOptions = ['priority', 'due_at', 'position', 'created_at', 'title'];
373 $orderOptions = ['ASC', 'DESC'];
374
375 // Validate order and orderBy parameters
376 if (!in_array($order, $sortOptions) || !in_array($orderBy, $orderOptions)) {
377 throw new \Exception(__('Invalid sort or orderBy parameter', 'fluent-boards'));
378 }
379
380 $tasksQuery = Task::where('stage_id', $stage_id)
381 ->whereNull('parent_id')
382 ->whereNull('archived_at')
383 ->with(['assignees', 'labels', 'watchers']);
384
385 // Apply ordering based on the specified order and orderBy
386 switch ($order) {
387 case 'priority':
388 $tasksQuery->orderByRaw("FIELD(priority, 'High', 'Medium', 'Low') {$orderBy}");
389 break;
390
391 case 'due_at':
392 if ($orderBy === 'ASC') {
393 // Separate ordering for tasks with and without due dates
394 $tasksWithDueDate = (clone $tasksQuery)->whereNotNull('due_at')->orderBy('due_at')->get();
395 $tasksWithoutDueDate = (clone $tasksQuery)->whereNull('due_at')->get();
396 $tasks = $tasksWithDueDate->merge($tasksWithoutDueDate);
397 } else {
398 $tasksQuery->orderBy('due_at', $orderBy);
399 }
400 break;
401
402 default:
403 $tasksQuery->orderBy($order, $orderBy);
404 break;
405 }
406
407 // Fetch tasks if not already fetched
408 if (!isset($tasks)) {
409 $tasks = $tasksQuery->get();
410 }
411
412 // Update tasks with additional attributes
413 $tasks->each(function ($task, $key) {
414 $task->position = $key + 1;
415 $task->save();
416 $task->isOverdue = $task->isOverdue();
417 $task->isUpcoming = $task->upcoming();
418 $task->is_watching = $task->isWatching();
419 $task->contact = Task::lead_contact($task->crm_contact_id);
420 });
421 return $tasks;
422 }
423
424
425 public function updateStage($updatedStage, $board_id, $oldStage)
426 {
427 $stageBeforeUpdate = clone $oldStage;
428 $oldStage->title = sanitize_text_field(Arr::get($updatedStage, 'title'));
429 $oldStage->bg_color = sanitize_text_field(Arr::get($updatedStage, 'cover_bg'));
430 $oldStage->save();
431 do_action('fluent_boards/stage_updated', $board_id, $updatedStage, $stageBeforeUpdate);
432 return $oldStage;
433 }
434
435 public function setDefaultAssignees($stage_id, $assignees)
436 {
437 $stage = Stage::findOrFail($stage_id);
438 if ($stage) {
439 $oldSettings = $stage->settings;
440 $oldSettings['default_task_assignees'] = $assignees;
441 $stage->settings = $oldSettings;
442 $stage->save();
443
444 do_action('fluent_boards/default_assignees_updated', $stage, $assignees);
445
446 return $stage;
447 }
448 }
449 }
450