PluginProbe
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration / 1.31
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration v1.31
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 / Http / Controllers / BoardController.php

BoardController.php in FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration 1.31, at app/Http/Controllers/BoardController.php

951 lines 30.8 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\Http\Controllers;
4
5 use FluentBoards\App\Models\Meta;
6 use FluentBoards\App\Models\Relation;
7 use FluentBoards\App\Models\Task;
8 use FluentBoards\App\Models\User;
9 use FluentBoards\App\Models\Board;
10 use FluentBoards\App\Services\Constant;
11 use FluentBoards\App\Services\Helper;
12 use FluentBoards\App\Models\Stage;
13 use FluentBoards\App\Services\InstallService;
14 use FluentBoards\App\Services\StageService;
15 use FluentBoards\App\Services\TaskService;
16 use FluentBoards\App\Services\BoardService;
17 use FluentBoards\App\Services\UserService;
18 use FluentBoards\Framework\Http\Request\Request;
19 use FluentBoards\App\Services\PermissionManager;
20 use FluentBoards\App\Hooks\Handlers\BoardHandler;
21 use FluentBoards\App\Services\LabelService;
22 use FluentBoards\Framework\Support\Arr;
23 use FluentBoards\Framework\Support\Collection;
24 use FluentCrm\App\Models\Subscriber;
25
26 class BoardController extends Controller
27 {
28 private $boardService;
29 private $taskService;
30 private $stageService;
31 private $labelService;
32
33 public function __construct(
34 BoardService $boardService,
35 TaskService $taskService,
36 StageService $stageService,
37 LabelService $labelService
38 )
39 {
40 parent::__construct();
41 $this->boardService = $boardService;
42 $this->taskService = $taskService;
43 $this->stageService = $stageService;
44 $this->labelService = $labelService;
45 }
46
47 public function getBoards(Request $request)
48 {
49 $per_page = $request->getSafe('per_page', 'intval', 20);
50 $userId = get_current_user_id();
51 $type = $request->getSafe('type', 'sanitize_text_field', 'to-do');
52
53 $order = $request->getSafe('order', 'sanitize_text_field', 'created_at');
54 $orderBy = $request->getSafe('orderBy', 'sanitize_text_field', 'DESC');
55 $searchInput = $request->getSafe('searchInput', 'sanitize_text_field');
56
57 $option = $request->getSafe('option', 'sanitize_text_field');
58
59 if(!defined('FLUENT_ROADMAP'))
60 {
61 if($option == 'archived') {
62 $relatedBoardsQuery = Board::whereNotNull('archived_at')->where('type', 'to-do')->byAccessUser($userId);
63 } else {
64 $relatedBoardsQuery = Board::whereNull('archived_at')->where('type', 'to-do')->byAccessUser($userId);
65 }
66 } else {
67 if($option == 'archived') {
68 $relatedBoardsQuery = Board::whereNotNull('archived_at')->byAccessUser($userId);
69 } else {
70 $relatedBoardsQuery = Board::whereNull('archived_at')->byAccessUser($userId);
71 }
72 }
73
74 if (!empty($searchInput)) {
75 $relatedBoardsQuery = $relatedBoardsQuery->where('title', 'like', '%' . $searchInput . '%');
76 }
77
78 $relatedBoards = $relatedBoardsQuery->orderBy($order, $orderBy)
79 ->withCount('completedTasks')
80 ->with('stages', 'users')
81 ->paginate($per_page);
82
83 foreach ($relatedBoards as $relatedBoard) {
84 $relatedBoard->users = Helper::sanitizeUserCollections($relatedBoard->users);
85 }
86
87 return $this->sendSuccess([
88 'boards' => $relatedBoards
89 ], 200);
90 }
91
92 /**
93 * Get the list of boards and their associated stages for the current user.
94 *
95 * @param \FluentBoards\Framework\Http\Request\Request $request
96 * @return \WP_REST_Response
97 */
98 public function getBoardsList(Request $request)
99 {
100 try {
101 $userId = get_current_user_id();
102
103 // Query to fetch boards that are not archived and accessible by the user
104 // Check if the FLUENT_ROADMAP constant is defined
105 if (!defined('FLUENT_ROADMAP')) {
106 $relatedBoardsQuery = Board::whereNull('archived_at')->where('type', 'to-do')->byAccessUser($userId);
107 } else {
108 $relatedBoardsQuery = Board::whereNull('archived_at')->byAccessUser($userId);
109 }
110
111 $relatedBoards = $relatedBoardsQuery->with('stages')->get();
112
113 // Fetch the stages associated with the boards
114 $stages = Stage::whereIn('board_id', $relatedBoards->pluck('id'))->where('archived_at', null)->get();
115
116 return $this->sendSuccess([
117 'boards' => $relatedBoards,
118 'all_stages' => $stages,
119 ], 200);
120 } catch (\Exception $e) {
121 return $this->sendError($e->getMessage(), 404);
122 }
123 }
124
125 public function getRecentBoards()
126 {
127 $boards = $this->boardService->getRecentBoards();
128
129 if (!$boards || $boards->isEmpty()) {
130 $boards = Board::where('type', 'to-do')->byAccessUser(get_current_user_id())
131 ->limit(4)
132 ->withCount('completedTasks')
133 ->with(['stages', 'users'])
134 ->get();
135 }
136
137 foreach ($boards as $board) {
138 $board->users = Helper::sanitizeUserCollections($board->users);
139 }
140
141 return [
142 'boards' => $boards,
143 ];
144 }
145
146 /*
147 * TODO: Refactor this method , remove this
148 */
149 public function getBoardsByType($type)
150 {
151 $boards = $this->boardService->getBoardsByType($type);
152
153 return $this->sendSuccess([
154 'boards' => $boards,
155 ], 200);
156 }
157
158 public function createFirstBoard(Request $request)
159 {
160 $boardData = $this->boardSanitizeAndValidate($request->get('board'), [
161 'title' => 'required|string',
162 'description' => 'nullable',
163 'type' => 'required|string',
164 'currency' => 'nullable|string',
165 'crm_contact_id' => 'nullable|numeric',
166 ]);
167
168 $installFluentCRM = $request->get('withFluentCRM') == 'yes' ? true : false;
169
170 $postStages = $request->get('stages');
171 $stageData = array();
172 foreach ($postStages as $stage) {
173 $temp = $this->stageSanitizeAndValidate($stage, [
174 'title' => 'required|string',
175 ]);
176 $stageData[] = $temp;
177 }
178
179 $taskData = null;
180 if ($request->get('task')) {
181 $taskData = $this->taskSanitizeAndValidate($request->get('task'), [
182 'title' => 'required|string'
183 ]);
184 }
185
186 $board = $this->boardService->createBoard($boardData);
187 $this->labelService->createDefaultLabel($board->id);
188 $type = ucfirst($boardData['type']);
189 $stage = $this->stageService->createStages($board, $stageData);
190
191 if ($taskData) {
192 $taskData['board_id'] = $board->id;
193 $taskData['stage_id'] = $stage->id;
194 $this->taskService->createTask($taskData, $board->id);
195 }
196
197 do_action('fluent_boards/board_created', $board);
198
199 if ($installFluentCRM && !defined('FLUENTCRM')) {
200 InstallService::install('fluent-crm');
201 }
202
203 return [
204 'message' => __('Board has been created', 'fluent-boards'),
205 'board' => $board,
206 ];
207 }
208
209 public function skipOnboarding(Request $request)
210 {
211 $onboarding = Meta::where('key', Constant::FBS_ONBOARDING)->first();
212 if($onboarding && $onboarding->value == 'no'){
213 $onboarding->value = 'yes' ;
214 $onboarding->save();
215 }
216
217 return [
218 'message' => __('Onboarding skipped successfully', 'fluent-boards'),
219 ];
220 }
221
222 public function create(Request $request)
223 {
224 $boardData = $this->boardSanitizeAndValidate($request->get('board'), [
225 'title' => 'required|string',
226 'description' => 'nullable',
227 'type' => 'required|string',
228 'currency' => 'nullable|string',
229 'crm_contact_id' => 'nullable|numeric',
230 ]);
231
232 try {
233 $board = $this->boardService->createBoard($boardData);
234 $this->labelService->createDefaultLabel($board->id);
235 $type = ucfirst($boardData['type']);
236
237 if (isset($boardData['type']) && $boardData['type'] == 'roadmap') {
238 $this->stageService->createRoadmapStages($board, $request->get('stages'));
239 } else {
240 $this->stageService->createDefaultStages($board);
241 }
242
243 // if board is created from crm contact
244 if (isset($boardData['crm_contact_id'])) {
245 $this->boardService->updateAssociateMember($boardData['crm_contact_id'], $board->id);
246 }
247
248 do_action('fluent_boards/board_created', $board);
249
250 $message = __('Board has been created successfully', 'fluent-boards');
251
252 return $this->sendSuccess([
253 'message' => $message,
254 'board' => $board,
255 ], 201);
256 } catch (\Exception $e) {
257 return $this->sendError($e->getMessage(), 400);
258 }
259 }
260
261 public function getArchivedStage(Request $request, $board_id)
262 {
263 try {
264 $pagination = $request->noPagination ? true : false;
265 $per_page = isset($data['per_page']) ? $data['per_page'] : 30;
266 $page = isset($data['page']) ? $data['page'] : 1;
267 if ($pagination) {
268 $stages = Stage::where('board_id', $board_id)
269 ->whereNotNull('archived_at')
270 ->orderBy('created_at', 'DESC')
271 ->get();
272 } else {
273 $stages = Stage::where('board_id', $board_id)
274 ->whereNotNull('archived_at')
275 ->orderBy('created_at', 'DESC')
276 ->paginate($per_page, ['*'], 'page', $page);
277 }
278
279 return $this->sendSuccess([
280 'stages' => $stages,
281 ], 200);
282 } catch (\Exception $e) {
283 return $this->sendError($e->getMessage(), 404);
284 }
285 }
286
287 public function find($board_id)
288 {
289 $board = Board::findOrFail($board_id);
290 $board->background = maybe_unserialize($board->background);
291 $board->createdOn = $board->created_at->format('Y-m-d');
292
293 $board->load(['users', 'stages', 'labels', 'owner']);
294
295 if (defined('FLUENT_BOARDS_PRO')){
296 $board->load(['customFields']);
297 }
298
299 $this->boardService->updateRecentBoards($board_id);
300
301 $board->labelColor = Constant::TRELLO_COLOR_MAP;
302 $board->labelColorText = Constant::TEXT_COLOR_MAP;
303
304 $board->users = Helper::sanitizeUserCollections($board->users);
305 $board->owner = Helper::sanitizeUserCollections($board->owner);
306
307 $board = apply_filters('fluent_boards/board_find', $board);
308
309 return [
310 'board' => $board
311 ];
312 }
313
314 public function update(Request $request, $board_id)
315 {
316 $boardData = $this->boardSanitizeAndValidate($request->only(['title', 'description']), [
317 'title' => 'required|string',
318 'description' => 'nullable|string',
319 ]);
320
321 $board = Board::findOrFail($board_id);
322
323 $oldBoard = clone $board;
324 $board->fill($boardData);
325 $board->save();
326
327 do_action('fluent_boards/board_updated', $board, $oldBoard);
328
329 return [
330 'stages' => $board->stages()->get(),
331 'message' => __('Board has been updated', 'fluent-boards'),
332 'board' => $board,
333 ];
334 }
335
336 public function archiveStage($board_id, $stage_id)
337 {
338 try {
339 $stage = Stage::findOrFail($stage_id);
340 $board = Board::findOrFail($stage->board_id);
341
342 $updatedStage = $this->boardService->archiveStage($board->id, $stage);
343
344 return $this->sendSuccess([
345 'updatedStage' => $updatedStage,
346 'message' => __('Stage has been archived', 'fluent-boards'),
347 ], 200);
348 } catch (\Exception $e) {
349 return $this->sendError($e->getMessage(), 400);
350 }
351 }
352
353 public function restoreStage($board_id, $stage_id)
354 {
355 try {
356 $stage = Stage::findOrFail($stage_id);
357 $board = Board::findOrFail($board_id);
358
359 $updatedStage = $this->boardService->restoreStage($board->id, $stage);
360
361 return $this->sendSuccess([
362 'success' => true,
363 'updatedStage' => $updatedStage,
364 'message' => __('Stage has been restored', 'fluent-boards')
365 ], 200);
366 } catch (\Exception $e) {
367 return $this->sendError($e->getMessage(), 400);
368 }
369 }
370
371
372 public function changePositionOfStage(Request $request, $board_id)
373 {
374 $changeData = $this->boardSanitizeAndValidate($request->only(['fromPosition', 'toPosition']), [
375 'fromPosition' => 'required',
376 'toPosition' => 'required',
377 ]);
378
379 try {
380 $this->boardService->changePositionOfStage($board_id, $changeData);
381
382 return $this->sendSuccess([
383 'message' => __('Board stage has been updated', 'fluent-boards')
384 ], 200);
385 } catch (\Exception $e) {
386 return $this->sendError($e->getMessage(), 400);
387 }
388 }
389
390 public function rePositionStages(Request $request, $board_id)
391 {
392 $incomingList = $request->get('list');
393 try {
394 $this->boardService->rePositionStages($board_id, $incomingList);
395 return $this->sendSuccess([
396 'message' => __('Stages Reordered', 'fluent-boards'),
397 'updatedStages' => $this->stageService->getLastOneMinuteUpdatedStages($board_id)
398 ], 200);
399 } catch (\Exception $e) {
400 return $this->sendError($e->getMessage(), 400);
401 }
402 }
403
404 public function getAssigneesByBoard($board_id)
405 {
406 return $this->sendSuccess([
407 'data' => $this->boardService->getAssigneesByBoard($board_id),
408 ], 200);
409 }
410
411 public function delete($board_id)
412 {
413 try {
414 if (!PermissionManager::isAdmin()) {
415 throw new \Exception('You do not have permission to delete this board', 400);
416 }
417 $this->boardService->deleteBoard($board_id);
418
419 return $this->sendSuccess([
420 'message' => __('Board has been deleted', 'fluent-boards'),
421 ], 200);
422 } catch (\Exception $e) {
423 return $this->sendError($e->getMessage(), 400);
424 }
425 }
426
427 public function getCurrencies()
428 {
429 return BoardHandler::getCurrencies();
430 }
431
432 public function getActivities(Request $request, $board_id)
433 {
434 try {
435 $activities = $this->boardService->getActivities($board_id, $request->all());
436 return $this->sendSuccess([
437 'activities' => $activities,
438 ], 200);
439 } catch (\Exception $e) {
440 return $this->sendError($e->getMessage(), 404);
441 }
442 }
443
444 /*
445 * TODO: Refactor this method - for Masiur
446 */
447 public function getBoardUsers($board_id)
448 {
449 $board = Board::findOrFail($board_id);
450
451 $boardObjects = Relation::where('object_type', 'board_user')
452 ->where('object_id', $board_id)
453 ->get()->keyBy('foreign_id');
454
455 $userIds = $boardObjects->pluck('foreign_id')->toArray();
456
457 $coreUsers = [];
458 if ($userIds) {
459 // Get the users who are in the board (members and managers
460 $coreUsers = get_users([
461 'include' => $userIds
462 ]);
463 }
464
465 $formattedUsers = [];
466
467 foreach ($coreUsers as $user) {
468 $name = trim($user->first_name . ' ' . $user->last_name);
469 if (!$name) {
470 $name = $user->display_name;
471 }
472
473 $boardRelation = $boardObjects[$user->ID] ?? null;
474
475 $formattedUsers[] = [
476 'ID' => $user->ID,
477 'display_name' => $name,
478 'email' => $user->user_email,
479 'photo' => fluent_boards_user_avatar($user->user_email, $name),
480 'role' => $boardRelation && $boardRelation->settings['is_admin'] ? 'manager' : 'member'
481 ];
482 }
483
484 // order formatted users by display_name
485 usort($formattedUsers, function ($a, $b) {
486 return strcmp($a['display_name'], $b['display_name']);
487 });
488
489 $returnData = [
490 'users' => Helper::sanitizeUsersArray($formattedUsers, $board_id),
491 'global_admins' => []
492 ];
493
494 if (!PermissionManager::isAdmin(get_current_user_id())) {
495 return $returnData;
496 }
497
498 /*
499 * These are the rest of the admin users who are not in the board
500 */
501 $adminUserIds = Meta::query()->where('object_type', Constant::FLUENT_BOARD_ADMIN)
502 ->whereNotIn('object_id', $userIds)
503 ->get()
504 ->pluck('object_id')
505 ->toArray();
506
507 if ($adminUserIds) {
508 $adminUsers = get_users([
509 'include' => $adminUserIds,
510 ]);
511
512 $formattedAdminUsers = [];
513
514 foreach ($adminUsers as $user) {
515 $name = trim($user->first_name . ' ' . $user->last_name);
516 if (!$name) {
517 $name = $user->display_name;
518 }
519
520 $formattedAdminUsers[] = [
521 'ID' => $user->ID,
522 'display_name' => $name,
523 'email' => $user->user_email,
524 'photo' => fluent_boards_user_avatar($user->user_email, $name),
525 'role' => 'admin'
526 ];
527 }
528
529 // order formatted users by display_name
530 usort($formattedAdminUsers, function ($a, $b) {
531 return strcmp($a['display_name'], $b['display_name']);
532 });
533
534 $returnData['global_admins'] = Helper::sanitizeUsersArray($formattedAdminUsers, $board_id);
535 }
536
537 return $this->sendSuccess($returnData, 200);
538 }
539
540
541 public function removeUserFromBoard($board_id, $userId)
542 {
543 $this->boardService->removeUserFromBoard($board_id, $userId);
544
545 if (!PermissionManager::isAdmin($userId)) {
546 $this->boardService->removeFromRecentlyOpened($board_id, $userId);
547 }
548
549 return [
550 'message' => __('Member removed successfully', 'fluent-boards'),
551 ];
552 }
553
554 public function addMembersInBoard(Request $request, $board_id)
555 {
556 $memberId = $request->getSafe('memberId');
557 $isAlreadyMember = $this->boardService->isAlreadyMember($board_id, $memberId);
558
559 if ($isAlreadyMember) {
560 return $this->sendError([
561 'message' => __('User already a member', 'fluent-boards'),
562 ], 304);
563 }
564 $member = $this->boardService->addMembersInBoard($board_id, $memberId);
565
566 return [
567 'message' => __('Member added successfully', 'fluent-boards'),
568 'member' => Helper::sanitizeUserCollections($member)
569 ];
570 }
571
572 private function boardSanitizeAndValidate($data, array $rules = [])
573 {
574 $data = Helper::sanitizeBoard($data);
575
576 return $this->validate($data, $rules);
577 }
578
579 private function stageSanitizeAndValidate($data, array $rules = [])
580 {
581 $data = Helper::sanitizeStage($data);
582
583 return $this->validate($data, $rules);
584 }
585
586 private function taskSanitizeAndValidate($data, array $rules = [])
587 {
588 $data = Helper::sanitizeTask($data);
589
590 return $this->validate($data, $rules);
591 }
592
593 public function searchBoards(Request $request)
594 {
595 $per_page = $request->get('per_page', 10);
596 $search_input = $request->searchInput . trim('');
597 $type = $request->type;
598
599 $currentUserId = get_current_user_id();
600
601 if (PermissionManager::isAdmin($currentUserId)) {
602 $boards = Board::query()->where('type', $type)
603 ->where('title', 'like', '%' . $search_input . '%')
604 ->with('stages', 'tasks', 'users')
605 ->paginate($per_page);
606
607 foreach ($boards as $board) {
608 $board->users = Helper::sanitizeUserCollections($board->users);
609 }
610
611 } else {
612 $currentUser = User::find($currentUserId);
613 $boards = $currentUser->boards()->where('type', $type)->where('title', 'like', '%' . $search_input . '%')->paginate($per_page);
614 }
615
616 return [
617 'boards' => $boards,
618 ];
619 }
620
621 public function getUsersOfBoards()
622 {
623 $userBoards = $this->boardService->getUsersOfBoards();
624
625 return $this->sendSuccess([
626 'userBoards' => $userBoards,
627 ], 200);
628 }
629
630
631
632 /**
633 * Refactor this code form me - Masiur
634 * change stage settings is_public for roadmap user and admin view
635 * @param $board_id
636 * @param $stage_id
637 * @return
638 */
639 public function changeStageView($board_id, $stage_id)
640 {
641 try {
642 $stage = Stage::findOrFail($stage_id);
643 $message = __('The stage is made public!', 'fluent-boards');
644 $settings = $stage->settings;
645
646 if (isset($settings['is_public'])) {
647 if ($settings['is_public']) {
648 $settings['is_public'] = false;
649 $message = __('The stage is made admin only!', 'fluent-boards');
650 } else {
651 $settings['is_public'] = true;
652 }
653 } else {
654 $settings['is_public'] = true;
655 }
656
657 $stage->settings = $settings;
658 $stage->save();
659 return $this->sendSuccess([
660 'message' => $message,
661 'stage' => $stage
662 ]);
663 } catch (\Exception $e) {
664 return $this->sendError($e->getMessage(), 400);
665 }
666 }
667
668
669 /**
670 * Set board background image or color
671 * @param \FluentBoards\Framework\Http\Request\Request $request
672 * @return
673 */
674 public function setBoardBackground(Request $request, $board_id)
675 {
676 // sanitize and validate image_url
677 if ($request->image_url) {
678 $backgroundData = $this->boardSanitizeAndValidate($request->all(), [
679 "id" => 'required',
680 'image_url' => 'required|string|url',
681 ]);
682 }
683
684 // sanitize and validate color
685 if ($request->color) {
686 $backgroundData = $this->boardSanitizeAndValidate($request->all(), [
687 "id" => 'required',
688 'color' => 'required',
689 ]);
690 }
691
692 try {
693 if (!$board_id) {
694 $errorMessage = __('Board id is required', 'fluent-boards');
695 throw new \Exception($errorMessage, 400);
696 }
697
698 return $this->sendSuccess([
699 'message' => __('Background updated successfully', 'fluent-boards'),
700 'background' => $this->boardService->setBoardBackground($backgroundData, $board_id),
701 ]);
702 } catch (\Exception $e) {
703 $this->sendError([$e->getMessage(), 400]);
704 }
705 }
706
707
708 /**
709 * Summary of getStageTaskAvailablePositions
710 * @param mixed $board_id
711 * @param mixed $stage_slug
712 * @return $availablePositions as an array
713 * @throws \Exception
714 */
715 public function getStageTaskAvailablePositions($board_id, $stage_id)
716 {
717 try {
718 if ($board_id && $stage_id) {
719 $availablePositions = $this->boardService->getStageTaskAvailablePositions($board_id, $stage_id);
720 return $this->sendSuccess([
721 'availablePositions' => $availablePositions
722 ], 200);
723 } else {
724 $message = '';
725 if (!$board_id) {
726 $message = 'Board id ';
727 }
728 if (!$stage_id) {
729 $message = 'Stage ';
730 }
731 throw new \Exception($message . 'is required', 400);
732 }
733 } catch (\Exception $e) {
734 $this->sendError([$e->getMessage(), 400]);
735 }
736 }
737
738 public function getAssociateCrmContacts($board_id)
739 {
740 try {
741 $contactAssociatedTasks = Task::with('board')->where('board_id', $board_id)
742 ->whereNotNull('crm_contact_id')
743 ->get();
744
745 $formattedContacts = Collection::make($contactAssociatedTasks)
746 ->groupBy('crm_contact_id')
747 ->map(function ($tasks, $contactId) {
748 $subscriber = Subscriber::find($contactId);
749 if (!$subscriber) {
750 return null; // Skip if subscriber not found
751 }
752
753 return [
754 'name' => $subscriber->first_name . ' ' . $subscriber->last_name,
755 'photo' => $subscriber->photo,
756 'email' => $subscriber->email,
757 'crm_contact_id' => $contactId,
758 'id' => $contactId,
759 'tasks' => $tasks,
760 ];
761 })
762 ->filter()->toArray();
763
764
765 return $this->sendSuccess([
766 'associatedContacts' => $formattedContacts
767 ], 200);
768 } catch (\Exception $e) {
769 return $this->sendError($e->getMessage(), 404);
770 }
771 }
772
773 public function updateAssociateCrmContact(Request $request, $board_id)
774 {
775 $value = $request->getSafe('value');
776 $this->boardService->updateAssociateMember($value, $board_id);
777
778 return $this->sendSuccess([
779 'message' => __('Associated Crm Member has been updated', 'fluent-boards'),
780 ], 200);
781 }
782
783 public function hasDataChanged($board_id)
784 {
785 return $this->boardService->hasDataChanged($board_id);
786 }
787
788 public function createStage(Request $request, $board_id)
789 {
790 $stageData = $this->stageSanitizeAndValidate($request->all(), [
791 'title' => 'required|string',
792 ]);
793
794 $board = Board::find($board_id);
795 $stage = $this->stageService->createStage($stageData, $board_id);
796
797 do_action('fluent_boards/board_stage_added', $board, $stage);
798
799 $updatedStates = (new StageService())->getLastOneMinuteUpdatedStages($board_id);
800
801 return [
802 'updatedStages' => $updatedStates,
803 'message' => __('stage has been created', 'fluent-boards'),
804 ];
805 }
806
807 public function moveAllTasks(Request $request, $board_id)
808 {
809 $oldStageId = $request->getSafe('oldStageId');
810 $newStageId = $request->getSafe('newStageId');
811
812 $updates = $this->stageService->moveAllTasks($oldStageId, $newStageId, $board_id);
813
814 return [
815 'message' => __('Tasks has been Moved', 'fluent-boards'),
816 'updatedTasks' => $updates,
817 ];
818
819 }
820
821 public function archiveAllTasksInStage($board_id, $stage_id)
822 {
823 $updates = $this->stageService->archiveAllTasksInStage($stage_id);
824 return [
825 'message' => __('Tasks has been archived', 'fluent-boards'),
826 'updatedTasks' => $updates,
827 ];
828 }
829
830 public function getAssociatedBoards(Request $request, $associated_id)
831 {
832 $associatedBoards = $this->boardService->getAssociatedBoards($associated_id);
833 return [
834 'boards' => $associatedBoards,
835 ];
836 }
837
838 public function duplicateBoard(Request $request, $board_id)
839 {
840 $boardData = $this->taskSanitizeAndValidate($request->get('board'), [
841 'title' => 'required|string'
842 ]);
843 $isWithLabels = $request->getSafe('isWithLabels');
844 $isWithTasks = $request->getSafe('isWithTasks');
845
846 try {
847 if(!PermissionManager::isAdmin()) {
848 $errorMessage = __('You do not have permission to duplicate board', 'fluent-boards');
849 throw new \Exception($errorMessage, 400);
850 }
851 //create board
852 $newBoard = $this->boardService->copyBoard($boardData);
853
854 //label copy
855 $labelMap = [];
856
857 if ($isWithLabels == 'yes') {
858 $labelMap = $this->labelService->copyLabelsOfBoard($board_id, $newBoard);
859 }
860
861 //stage copy
862 $stageMapForCopyingTask = $this->stageService->copyStagesOfBoard($newBoard, $board_id);
863
864 //copy tasks of selected stages
865 if ($isWithTasks == 'yes') {
866 $this->taskService->copyTasks($board_id, $stageMapForCopyingTask, $newBoard, $labelMap);
867 }
868
869 return $this->sendSuccess([
870 'board' => $newBoard,
871 ], 200);
872 } catch (\Exception $e) {
873 return $this->sendError($e->getMessage(), 400);
874 }
875 }
876
877 public function importFromBoard(Request $request, $board_id)
878 {
879 $selectedStages = $request->getSafe('selectedStages');
880
881 try {
882 $this->stageService->importStagesFromBoard($board_id, $selectedStages);
883
884 return $this->sendSuccess([
885 'message' => __('Import successfully', 'fluent-boards'),
886 ], 200);
887
888 } catch (\Exception $e) {
889 return $this->sendError($e->getMessage(), 400);
890 }
891 }
892
893 public function getBoardDefaultBackgroundColors()
894 {
895 return [
896 'solidColors' => Constant::BOARD_BACKGROUND_DEFAULT_SOLID_COLORS,
897 'gradients' => Constant::BOARD_BACKGROUND_DEFAULT_GRADIENT_COLORS
898 ];
899 }
900
901 /*
902 * TODO: For Masiur - I will update this later
903 */
904 public function updateBoardProperties(Request $request, $board_id)
905 {
906 $pageId = $request->getSafe('page_id');
907 $enable_stage_change_email = $request->getSafe('enable_stage_change_email');
908
909 $board = Board::findOrFail($board_id);
910
911 $board->updateMeta('roadmap_page_id', $pageId);
912 $board->updateMeta('enable_stage_change_email', $enable_stage_change_email);
913
914 $board = $board->fresh();
915
916 return [
917 'message' => __('Board has been updated', 'fluent-boards'),
918 'board' => apply_filters('fluent_boards/board_find', $board)
919 ];
920 }
921
922 public function archiveBoard($board_id)
923 {
924 try {
925 $board = $this->boardService->archiveBoard($board_id);
926
927 return [
928 'board' => $board,
929 'message' => __('Board has been archived successfully!', 'fluent-boards')
930 ];
931 } catch (\Exception $e) {
932 return $this->sendError($e->getMessage(), 400);
933 }
934 }
935
936 public function restoreBoard($board_id)
937 {
938 try {
939 $board = $this->boardService->restoreBoard($board_id);
940
941 return [
942 'board' => $board,
943 'message' => __('Board has been restored successfully!', 'fluent-boards')
944 ];
945 } catch (\Exception $e) {
946 return $this->sendError($e->getMessage(), 400);
947 }
948 }
949
950 }
951