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

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