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 / Http / Controllers / BoardController.php

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

969 lines 31.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\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 $superAdminIds = Meta::query()->where('object_type', Constant::FLUENT_BOARD_ADMIN)
456 ->get()->pluck('object_id')->toArray();
457
458 $userIds = $boardObjects->pluck('foreign_id')->toArray();
459
460 $coreUsers = [];
461 if ($userIds) {
462 // Get the users who are in the board (members and managers
463 $coreUsers = get_users([
464 'include' => $userIds
465 ]);
466 }
467
468 $formattedUsers = [];
469
470 foreach ($coreUsers as $user) {
471 $name = trim($user->first_name . ' ' . $user->last_name);
472 if (!$name) {
473 $name = $user->display_name;
474 }
475
476 $boardRelation = $boardObjects[$user->ID] ?? null;
477
478
479 $formattedUsers[] = [
480 'ID' => $user->ID,
481 'display_name' => $name,
482 'email' => $user->user_email,
483 'photo' => fluent_boards_user_avatar($user->user_email, $name),
484 'role' => $this->boardUserRole($boardRelation),
485 'is_super' => in_array($user->ID, $superAdminIds),
486 'is_wpadmin' => $user->has_cap('manage_options')
487 ];
488 }
489
490 // order formatted users by display_name
491 usort($formattedUsers, function ($a, $b) {
492 return strcmp($a['display_name'], $b['display_name']);
493 });
494
495 $returnData = [
496 'users' => Helper::sanitizeUsersArray($formattedUsers, $board_id),
497 'global_admins' => []
498 ];
499
500 if (!PermissionManager::isAdmin(get_current_user_id())) {
501 return $returnData;
502 }
503
504 /*
505 * These are the rest of the admin users who are not in the board
506 */
507 $adminUserIds = Meta::query()->where('object_type', Constant::FLUENT_BOARD_ADMIN)
508 ->whereNotIn('object_id', $userIds)
509 ->get()
510 ->pluck('object_id')
511 ->toArray();
512
513 if ($adminUserIds) {
514 $adminUsers = get_users([
515 'include' => $adminUserIds,
516 ]);
517
518 $formattedAdminUsers = [];
519
520 foreach ($adminUsers as $user) {
521 $name = trim($user->first_name . ' ' . $user->last_name);
522 if (!$name) {
523 $name = $user->display_name;
524 }
525
526 $formattedAdminUsers[] = [
527 'ID' => $user->ID,
528 'display_name' => $name,
529 'email' => $user->user_email,
530 'photo' => fluent_boards_user_avatar($user->user_email, $name),
531 'role' => 'admin',
532 'is_super' => in_array($user->ID, $superAdminIds),
533 'is_wpadmin' => $user->has_cap('manage_options')
534 ];
535 }
536
537 // order formatted users by display_name
538 usort($formattedAdminUsers, function ($a, $b) {
539 return strcmp($a['display_name'], $b['display_name']);
540 });
541
542 $returnData['global_admins'] = Helper::sanitizeUsersArray($formattedAdminUsers, $board_id);
543 }
544
545 return $this->sendSuccess($returnData, 200);
546 }
547
548
549 public function removeUserFromBoard($board_id, $userId)
550 {
551 $this->boardService->removeUserFromBoard($board_id, $userId);
552
553 if (!PermissionManager::isAdmin($userId)) {
554 $this->boardService->removeFromRecentlyOpened($board_id, $userId);
555 }
556
557 return [
558 'message' => __('Member removed successfully', 'fluent-boards'),
559 ];
560 }
561
562 public function addMembersInBoard(Request $request, $board_id)
563 {
564 $memberId = $request->getSafe('memberId');
565 $isViewerOnly = $request->getSafe('isViewerOnly');
566 $isAlreadyMember = $this->boardService->isAlreadyMember($board_id, $memberId);
567
568 if ($isAlreadyMember) {
569 return $this->sendError([
570 'message' => __('User already a member', 'fluent-boards'),
571 ], 304);
572 }
573 $member = $this->boardService->addMembersInBoard($board_id, $memberId, $isViewerOnly);
574
575 return [
576 'message' => __('Member added successfully', 'fluent-boards'),
577 'member' => Helper::sanitizeUserCollections($member)
578 ];
579 }
580
581 private function boardSanitizeAndValidate($data, array $rules = [])
582 {
583 $data = Helper::sanitizeBoard($data);
584
585 return $this->validate($data, $rules);
586 }
587
588 private function stageSanitizeAndValidate($data, array $rules = [])
589 {
590 $data = Helper::sanitizeStage($data);
591
592 return $this->validate($data, $rules);
593 }
594
595 private function taskSanitizeAndValidate($data, array $rules = [])
596 {
597 $data = Helper::sanitizeTask($data);
598
599 return $this->validate($data, $rules);
600 }
601
602 public function searchBoards(Request $request)
603 {
604 $per_page = $request->get('per_page', 10);
605 $search_input = $request->searchInput . trim('');
606 $type = $request->type;
607
608 $currentUserId = get_current_user_id();
609
610 if (PermissionManager::isAdmin($currentUserId)) {
611 $boards = Board::query()->where('type', $type)
612 ->where('title', 'like', '%' . $search_input . '%')
613 ->with('stages', 'tasks', 'users')
614 ->paginate($per_page);
615
616 foreach ($boards as $board) {
617 $board->users = Helper::sanitizeUserCollections($board->users);
618 }
619
620 } else {
621 $currentUser = User::find($currentUserId);
622 $boards = $currentUser->boards()->where('type', $type)->where('title', 'like', '%' . $search_input . '%')->paginate($per_page);
623 }
624
625 return [
626 'boards' => $boards,
627 ];
628 }
629
630 public function getUsersOfBoards()
631 {
632 $userBoards = $this->boardService->getUsersOfBoards();
633
634 return $this->sendSuccess([
635 'userBoards' => $userBoards,
636 ], 200);
637 }
638
639
640
641 /**
642 * Refactor this code form me - Masiur
643 * change stage settings is_public for roadmap user and admin view
644 * @param $board_id
645 * @param $stage_id
646 * @return
647 */
648 public function changeStageView($board_id, $stage_id)
649 {
650 try {
651 $stage = Stage::findOrFail($stage_id);
652 $message = __('The stage is made public!', 'fluent-boards');
653 $settings = $stage->settings;
654
655 if (isset($settings['is_public'])) {
656 if ($settings['is_public']) {
657 $settings['is_public'] = false;
658 $message = __('The stage is made admin only!', 'fluent-boards');
659 } else {
660 $settings['is_public'] = true;
661 }
662 } else {
663 $settings['is_public'] = true;
664 }
665
666 $stage->settings = $settings;
667 $stage->save();
668 return $this->sendSuccess([
669 'message' => $message,
670 'stage' => $stage
671 ]);
672 } catch (\Exception $e) {
673 return $this->sendError($e->getMessage(), 400);
674 }
675 }
676
677
678 /**
679 * Set board background image or color
680 * @param \FluentBoards\Framework\Http\Request\Request $request
681 * @return
682 */
683 public function setBoardBackground(Request $request, $board_id)
684 {
685 // sanitize and validate image_url
686 if ($request->image_url) {
687 $backgroundData = $this->boardSanitizeAndValidate($request->all(), [
688 "id" => 'required',
689 'image_url' => 'required|string|url',
690 ]);
691 }
692
693 // sanitize and validate color
694 if ($request->color) {
695 $backgroundData = $this->boardSanitizeAndValidate($request->all(), [
696 "id" => 'required',
697 'color' => 'required',
698 ]);
699 }
700
701 try {
702 if (!$board_id) {
703 $errorMessage = __('Board id is required', 'fluent-boards');
704 throw new \Exception($errorMessage, 400);
705 }
706
707 return $this->sendSuccess([
708 'message' => __('Background updated successfully', 'fluent-boards'),
709 'background' => $this->boardService->setBoardBackground($backgroundData, $board_id),
710 ]);
711 } catch (\Exception $e) {
712 $this->sendError([$e->getMessage(), 400]);
713 }
714 }
715
716
717 /**
718 * Summary of getStageTaskAvailablePositions
719 * @param mixed $board_id
720 * @param mixed $stage_slug
721 * @return $availablePositions as an array
722 * @throws \Exception
723 */
724 public function getStageTaskAvailablePositions($board_id, $stage_id)
725 {
726 try {
727 if ($board_id && $stage_id) {
728 $availablePositions = $this->boardService->getStageTaskAvailablePositions($board_id, $stage_id);
729 return $this->sendSuccess([
730 'availablePositions' => $availablePositions
731 ], 200);
732 } else {
733 $message = '';
734 if (!$board_id) {
735 $message = 'Board id ';
736 }
737 if (!$stage_id) {
738 $message = 'Stage ';
739 }
740 throw new \Exception($message . 'is required', 400);
741 }
742 } catch (\Exception $e) {
743 $this->sendError([$e->getMessage(), 400]);
744 }
745 }
746
747 public function getAssociateCrmContacts($board_id)
748 {
749 try {
750 $contactAssociatedTasks = Task::with('board')->where('board_id', $board_id)
751 ->whereNotNull('crm_contact_id')
752 ->get();
753
754 $formattedContacts = Collection::make($contactAssociatedTasks)
755 ->groupBy('crm_contact_id')
756 ->map(function ($tasks, $contactId) {
757 $subscriber = Subscriber::find($contactId);
758 if (!$subscriber) {
759 return null; // Skip if subscriber not found
760 }
761
762 return [
763 'name' => $subscriber->first_name . ' ' . $subscriber->last_name,
764 'photo' => $subscriber->photo,
765 'email' => $subscriber->email,
766 'crm_contact_id' => $contactId,
767 'id' => $contactId,
768 'tasks' => $tasks,
769 ];
770 })
771 ->filter()->toArray();
772
773
774 return $this->sendSuccess([
775 'associatedContacts' => $formattedContacts
776 ], 200);
777 } catch (\Exception $e) {
778 return $this->sendError($e->getMessage(), 404);
779 }
780 }
781
782 public function updateAssociateCrmContact(Request $request, $board_id)
783 {
784 $value = $request->getSafe('value');
785 $this->boardService->updateAssociateMember($value, $board_id);
786
787 return $this->sendSuccess([
788 'message' => __('Associated Crm Member has been updated', 'fluent-boards'),
789 ], 200);
790 }
791
792 public function hasDataChanged($board_id)
793 {
794 return $this->boardService->hasDataChanged($board_id);
795 }
796
797 public function createStage(Request $request, $board_id)
798 {
799 $stageData = $this->stageSanitizeAndValidate($request->all(), [
800 'title' => 'required|string',
801 ]);
802
803 $board = Board::find($board_id);
804 $stage = $this->stageService->createStage($stageData, $board_id);
805
806 do_action('fluent_boards/board_stage_added', $board, $stage);
807
808 $updatedStates = (new StageService())->getLastOneMinuteUpdatedStages($board_id);
809
810 return [
811 'updatedStages' => $updatedStates,
812 'message' => __('stage has been created', 'fluent-boards'),
813 ];
814 }
815
816 public function moveAllTasks(Request $request, $board_id)
817 {
818 $oldStageId = $request->getSafe('oldStageId');
819 $newStageId = $request->getSafe('newStageId');
820
821 $updates = $this->stageService->moveAllTasks($oldStageId, $newStageId, $board_id);
822
823 return [
824 'message' => __('Tasks has been Moved', 'fluent-boards'),
825 'updatedTasks' => $updates,
826 ];
827
828 }
829
830 public function archiveAllTasksInStage($board_id, $stage_id)
831 {
832 $updates = $this->stageService->archiveAllTasksInStage($stage_id);
833 return [
834 'message' => __('Tasks has been archived', 'fluent-boards'),
835 'updatedTasks' => $updates,
836 ];
837 }
838
839 public function getAssociatedBoards(Request $request, $associated_id)
840 {
841 $associatedBoards = $this->boardService->getAssociatedBoards($associated_id);
842 return [
843 'boards' => $associatedBoards,
844 ];
845 }
846
847 public function duplicateBoard(Request $request, $board_id)
848 {
849 $boardData = $this->taskSanitizeAndValidate($request->get('board'), [
850 'title' => 'required|string'
851 ]);
852 $isWithLabels = $request->getSafe('isWithLabels');
853 $isWithTasks = $request->getSafe('isWithTasks');
854
855 try {
856 if(!PermissionManager::isAdmin()) {
857 $errorMessage = __('You do not have permission to duplicate board', 'fluent-boards');
858 throw new \Exception($errorMessage, 400);
859 }
860 //create board
861 $newBoard = $this->boardService->copyBoard($boardData);
862
863 //label copy
864 $labelMap = [];
865
866 if ($isWithLabels == 'yes') {
867 $labelMap = $this->labelService->copyLabelsOfBoard($board_id, $newBoard);
868 }
869
870 //stage copy
871 $stageMapForCopyingTask = $this->stageService->copyStagesOfBoard($newBoard, $board_id);
872
873 //copy tasks of selected stages
874 if ($isWithTasks == 'yes') {
875 $this->taskService->copyTasks($board_id, $stageMapForCopyingTask, $newBoard, $labelMap);
876 }
877
878 return $this->sendSuccess([
879 'board' => $newBoard,
880 ], 200);
881 } catch (\Exception $e) {
882 return $this->sendError($e->getMessage(), 400);
883 }
884 }
885
886 public function importFromBoard(Request $request, $board_id)
887 {
888 $selectedStages = $request->getSafe('selectedStages');
889
890 try {
891 $this->stageService->importStagesFromBoard($board_id, $selectedStages);
892
893 return $this->sendSuccess([
894 'message' => __('Import successfully', 'fluent-boards'),
895 ], 200);
896
897 } catch (\Exception $e) {
898 return $this->sendError($e->getMessage(), 400);
899 }
900 }
901
902 public function getBoardDefaultBackgroundColors()
903 {
904 return [
905 'solidColors' => Constant::BOARD_BACKGROUND_DEFAULT_SOLID_COLORS,
906 'gradients' => Constant::BOARD_BACKGROUND_DEFAULT_GRADIENT_COLORS
907 ];
908 }
909
910 /*
911 * TODO: For Masiur - I will update this later
912 */
913 public function updateBoardProperties(Request $request, $board_id)
914 {
915 $pageId = $request->getSafe('page_id');
916 $enable_stage_change_email = $request->getSafe('enable_stage_change_email');
917
918 $board = Board::findOrFail($board_id);
919
920 $board->updateMeta('roadmap_page_id', $pageId);
921 $board->updateMeta('enable_stage_change_email', $enable_stage_change_email);
922
923 $board = $board->fresh();
924
925 return [
926 'message' => __('Board has been updated', 'fluent-boards'),
927 'board' => apply_filters('fluent_boards/board_find', $board)
928 ];
929 }
930
931 public function archiveBoard($board_id)
932 {
933 try {
934 $board = $this->boardService->archiveBoard($board_id);
935
936 return [
937 'board' => $board,
938 'message' => __('Board has been archived successfully!', 'fluent-boards')
939 ];
940 } catch (\Exception $e) {
941 return $this->sendError($e->getMessage(), 400);
942 }
943 }
944
945 public function restoreBoard($board_id)
946 {
947 try {
948 $board = $this->boardService->restoreBoard($board_id);
949
950 return [
951 'board' => $board,
952 'message' => __('Board has been restored successfully!', 'fluent-boards')
953 ];
954 } catch (\Exception $e) {
955 return $this->sendError($e->getMessage(), 400);
956 }
957 }
958
959 private function boardUserRole($boardRelation)
960 {
961 return $boardRelation && Arr::get($boardRelation->settings, 'is_admin')
962 ? 'manager'
963 : ($boardRelation && Arr::has($boardRelation->settings, 'is_viewer_only') && Arr::get($boardRelation->settings, 'is_viewer_only')
964 ? 'viewer'
965 : 'member');
966 }
967
968 }
969