PluginProbe
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration / 1.21
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration v1.21
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.21, at app/Services/StageService.php

441 lines 14.3 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 $this->updateTitle($value, $stage);
64 } elseif ('status' == $col) {
65 $this->updateStatus($value, $stage);
66 } elseif ('color' == $col) {
67 $this->updateColor($value, $stage);
68 } elseif ('bg_color' == $col) {
69 $this->updateBackgroundColor($value, $stage);
70 } elseif ('archived_at' == $col) {
71 $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
87 }
88
89 private function updateStatus($value, $stage)
90 {
91 $oldSettings = $stage->settings;
92 $oldSettings['default_task_status'] = $value;
93 $stage->settings = $oldSettings;
94 $stage->save();
95 }
96
97 private function updateColor($value, $stage)
98 {
99
100 }
101
102 private function updateBackgroundColor($value, $stage)
103 {
104
105 }
106
107 private function updateArchivedAt($value, $stage)
108 {
109
110 }
111
112 public function createStage($stageData, $boardId)
113 {
114 $stage = new Stage();
115 $stage->board_id = $boardId;
116 $stage->title = $stageData['title'];
117 $stage->settings = [
118 'default_task_status' => Arr::get($stageData, 'status') ?? 'open'
119 ];
120 if (!Arr::get($stageData, 'position')) {
121 $lastStagePosition = $this->getLastPositionOfStagesOfBoard($boardId);
122 $stage->position = $lastStagePosition ? $lastStagePosition->position + 1 : 1;
123 $stage->save();
124 } else {
125 $stage->position = (int)$stageData['position'];
126 $stage->save();
127 $this->moveOtherStages($stage);
128 }
129
130 return $stage;
131 }
132
133 public function getLastPositionOfStagesOfBoard($boardId)
134 {
135 // return last position of stages of board
136 return Stage::where('board_id', $boardId)
137 ->whereNull('archived_at')
138 ->orderBy('position', 'desc')
139 ->first();
140 }
141
142 protected function moveOtherStages($stage)
143 {
144
145 $stages = Stage::where('board_id', $stage->board_id)
146 ->where('position', '>=', $stage->position)
147 ->whereNotIn('id', [$stage->id])
148 ->whereNull('archived_at')->get();
149
150 foreach ($stages as $stage) {
151 $stage->position = $stage->position + 1;
152 $stage->save();
153 }
154 }
155
156 public function copyStagesOfBoard($board, $fromBoardId)
157 {
158 $stages = Stage::where('board_id', $fromBoardId)->where('type', 'stage')->whereNull('archived_at')->get();
159 $stageMapForCopyingTask = array();
160 foreach($stages as $key => $stage)
161 {
162 $stageToSave = array();
163 $stageToSave['title'] = $stage['title'];
164 $stageToSave['board_id'] = $board->id;
165 $stageToSave['slug'] = str_replace(' ', '-', strtolower($stage['title']));
166 $stageToSave['type'] = 'stage';
167 $stageToSave['position'] = $key + 1;
168 $stageToSave['settings'] = [
169 'default_task_status' => $stage->settings['default_task_status']
170 ];
171 $newStage = Stage::create($stageToSave);
172 $stageMapForCopyingTask[$stage['id']] = $newStage->id;
173 }
174 return $stageMapForCopyingTask;
175 }
176
177 public function importStagesFromBoard($board_id, $selectedStages)
178 {
179 $targetStages = Stage::whereIn('id', $selectedStages)->get();
180 $stageMapForCopyingTask = array();
181 $stageIdsToCopy = array();
182
183 //need to define position of stage
184 $numberOfStages = Stage::where('board_id', $board_id)->whereNull('archived_at')->count();
185
186 foreach($targetStages as $key => $stage)
187 {
188 $stageToSave = array();
189 $stageToSave['title'] = $stage['title'] . ' - imported';
190 $stageToSave['board_id'] = $board_id;
191 $stageToSave['slug'] = str_replace(' ', '-', strtolower($stage['title']));
192 $stageToSave['type'] = 'stage';
193 $stageToSave['position'] = $numberOfStages + $key + 1;
194 $stageToSave['settings'] = [
195 'default_task_status' => $stage->settings['default_task_status']
196 ];
197 $newStage = Stage::create($stageToSave);
198 $stageMapForCopyingTask[$stage['id']] = $newStage->id;
199 $stageIdsToCopy[] = $stage['id'];
200 }
201
202 $this->importTasks($board_id, $stageMapForCopyingTask, $stageIdsToCopy);
203 }
204
205 public function importTasks($boardId, $stageMapper, $stageIds)
206 {
207 $tasksToImport = Task::whereIn('stage_id', $stageIds)->whereNull('archived_at')->get();
208
209 foreach($tasksToImport as $task)
210 {
211 $newTask = array();
212 $newTask['title'] = $task->title;
213 $newTask['description'] = $task->description;
214 $newTask['board_id'] = $boardId;
215 $newTask['stage_id'] = $stageMapper[$task->stage_id];
216 $newTask['status'] = $task->status;
217 $newTask['priority'] = $task->priority;
218 $newTask['position'] = $task->position;
219 $newTask['due_at'] = $task->due_at;
220 Task::create($newTask);
221 }
222
223 //update task count of board
224 $totalTasks = sizeof($tasksToImport);
225 $board = Board::findOrFail($boardId);
226 $settings = $board->settings ?? [];
227
228 if (isset($settings['tasks_count'])) {
229 $settings['tasks_count'] += $totalTasks;
230 } else {
231 $settings['tasks_count'] = $totalTasks;
232 }
233 $board->settings = $settings;
234 $board->save();
235 }
236
237 public function updateStageTemplate($stage_id)
238 {
239 $stage = Stage::findOrFail($stage_id);
240 $stageSettings = $stage->settings;
241 if($stageSettings && array_key_exists('is_template', $stageSettings))
242 {
243 $currentlyIsTemplate = $stageSettings['is_template'];
244 if($currentlyIsTemplate){
245 $stageSettings['is_template'] = false;
246 $stage->settings = $stageSettings;
247 }else{
248 $stageSettings['is_template'] = true;
249 $stage->settings = $stageSettings;
250 }
251 }else {
252 if(!$stageSettings) {
253 $stage->settings = [
254 'is_template' => true
255 ];
256 } else {
257 $stage->settings = array_merge($stage->settings, [
258 'is_template' => true
259 ]);
260 }
261
262 }
263 $stage->save();
264
265 return $stage;
266 }
267
268 public function moveAllTasks($oldStageId, $newStageId)
269 {
270 $tasks = Task::where('stage_id', $oldStageId)->whereNull('parent_id')->whereNull('archived_at')->get();
271
272 // get the last position available of that stage
273 $position = (new TaskService())->getLastPositionOfTasks($newStageId);
274
275 // update tasks stage and position
276 foreach ($tasks as $key => $task) {
277 $task->stage_id = $newStageId;
278 $task->position = $position + $key;
279 $task->save();
280 }
281 return $tasks;
282 }
283 public function archiveAllTasksInStage($stage_id)
284 {
285 $tasks = Task::where('stage_id', $stage_id)->whereNull('parent_id')->whereNull('archived_at')->get();
286 foreach ($tasks as $task) {
287 $task->position = 0;
288 $task->archived_at = current_time('mysql');
289 $task->save();
290 do_action('fluent_boards/board_task_archived', $task);
291 }
292 return $tasks;
293 }
294
295 public function createRoadmapStages($board, $stagesData)
296 {
297 foreach ($stagesData as $index => $formStageData) {
298 $stage = new Stage();
299 $stage->board_id = $board->id;
300 $stage->title = $formStageData['title'];
301 $stage->slug = $formStageData['slug'];
302 $stage->position = $formStageData['position'] ? $formStageData['position'] : 1;
303 $stage->settings = $this->roadmapStageSetting($index);
304 $stage->save();
305 }
306 return $stagesData;
307 }
308
309 /*
310 * I have no idea what this function does, but I am doing it
311 * to make the code work
312 */
313 public function roadmapStageSetting($index)
314 {
315 return [
316 'is_public' => $index > 0 ? true : false,
317 'default_task_status' => 'open',
318 'is_template' => false,
319 ];
320 }
321
322
323 public function createStages($board, $stageData)
324 {
325 $firstStage = null;
326 foreach ($stageData as $index => $stage) {
327 $stageToPush = array();
328 $stageToPush['title'] = $stage['title'];
329 $stageToPush['board_id'] = $board->id;
330 $stageToPush['position'] = $index + 1;
331 $stageToPush['slug'] = $this->createSlug($stage['title']);
332
333 if (Arr::get($stage, 'title') == 'Completed') {
334 $stageToPush['settings'] = [
335 'default_task_status' => 'closed',
336 'is_template' => false
337 ];
338 }
339
340 $stage = Stage::create($stageToPush);
341 if($index == 0){
342 $firstStage = $stage;
343 }
344 }
345 return $firstStage;
346 }
347
348 private function createSlug($title)
349 {
350 return str_replace(' ', '-', strtolower($title));
351 }
352
353 public function stagesByBoardId($boardId)
354 {
355 return Stage::where('board_id', $boardId)->whereNull('archived_at')->get();
356 }
357
358
359
360 public function sortStageTasks($order, $orderBy, $stage_id)
361 {
362 $sortOptions = ['priority', 'due_at', 'position', 'created_at', 'title'];
363 $orderOptions = ['ASC', 'DESC'];
364
365 // Validate order and orderBy parameters
366 if (!in_array($order, $sortOptions) || !in_array($orderBy, $orderOptions)) {
367 throw new \Exception(__('Invalid sort or orderBy parameter', 'fluent-boards'));
368 }
369
370 $tasksQuery = Task::where('stage_id', $stage_id)
371 ->whereNull('parent_id')
372 ->whereNull('archived_at')
373 ->with(['assignees', 'labels', 'watchers']);
374
375 // Apply ordering based on the specified order and orderBy
376 switch ($order) {
377 case 'priority':
378 $tasksQuery->orderByRaw("FIELD(priority, 'High', 'Medium', 'Low') {$orderBy}");
379 break;
380
381 case 'due_at':
382 if ($orderBy === 'ASC') {
383 // Separate ordering for tasks with and without due dates
384 $tasksWithDueDate = (clone $tasksQuery)->whereNotNull('due_at')->orderBy('due_at')->get();
385 $tasksWithoutDueDate = (clone $tasksQuery)->whereNull('due_at')->get();
386 $tasks = $tasksWithDueDate->merge($tasksWithoutDueDate);
387 } else {
388 $tasksQuery->orderBy('due_at', $orderBy);
389 }
390 break;
391
392 default:
393 $tasksQuery->orderBy($order, $orderBy);
394 break;
395 }
396
397 // Fetch tasks if not already fetched
398 if (!isset($tasks)) {
399 $tasks = $tasksQuery->get();
400 }
401
402 // Update tasks with additional attributes
403 $tasks->each(function ($task, $key) {
404 $task->position = $key + 1;
405 $task->save();
406 $task->isOverdue = $task->isOverdue();
407 $task->isUpcoming = $task->upcoming();
408 $task->is_watching = $task->isWatching();
409 $task->contact = Task::lead_contact($task->crm_contact_id);
410 });
411 return $tasks;
412 }
413
414 public function checkStageEditable($stages, $toBeUpdatedStage)
415 {
416 $stageEditable = true;
417 if (empty(sanitize_text_field($toBeUpdatedStage['title']))) {
418 $stageEditable = false;
419 } else {
420 foreach ($stages as $stage) { // check if stage label is similar to any other stage label
421 if (strtolower($stage->title) == strtolower(trim($toBeUpdatedStage['title']))) {
422 $stageEditable = false;
423 break;
424 }
425 }
426 }
427
428 return $stageEditable;
429 }
430
431 public function updateStage($updatedStage, $board_id, $oldStage)
432 {
433 $oldTitle = $oldStage->title;
434 $oldStage->title = Arr::get($updatedStage, 'title');
435 $oldStage->bg_color = Arr::get($updatedStage, 'cover_bg');
436 $oldStage->save();
437 do_action('fluent_boards/board_stage_updated', $board_id, $updatedStage['title'], $oldTitle);
438 return $oldStage;
439 }
440 }
441