PluginProbe
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration / 2.1.0
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration v2.1.0
2.1.0 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 All 42 releases
← All changes | app/Services/BoardService.php +88 -26 2.0.12.1.0 View file →
@@ -2,8 +2,9 @@
2 2
3 3 namespace FluentBoards\App\Services;
4 4
5 5 use FluentBoards\App\Models\Activity;
6 +use FluentBoards\App\Models\Attachment;
6 7 use FluentBoards\App\Models\Board;
7 8 use FluentBoards\App\Models\Comment;
8 9 use FluentBoards\App\Models\Folder;
9 10 use FluentBoards\App\Models\Label;
@@ -149,9 +150,9 @@
149 150 {
150 151 $boardData = [
151 152 'title' => $boardData['title'],
152 153 'type' => $boardData['type'] ? $boardData['type'] : 'to-do',
153 - 'description' => DescriptionMarkdownConverter::normalize($boardData['description']),
154 + 'description' => DescriptionMarkdownConverter::normalize($boardData['description'] ?? ''),
154 155 'currency' => isset($boardData['currency']) ? $boardData['currency'] : 'USD',
155 156 'background' => isset($boardData['background']) ? $boardData['background'] : '',
156 157 'created_by' => isset($boardData['created_by']) ? $boardData['created_by'] : get_current_user_id()
157 158 ];
@@ -372,14 +373,29 @@
372 373
373 374 return $isAlreadyMember ?? false;
374 375 }
375 376
377 + /**
378 + * Add a WordPress user to a board.
379 + *
380 + * @return User|false|null User on success, false for an existing relation,
381 + * or null when the board/user does not exist.
382 + */
376 383 public function addMembersInBoard($boardId, $memberId, $isViewerOnly = null)
377 384 {
385 + $boardId = intval($boardId);
386 + $memberId = intval($memberId);
387 + $isViewerOnly = sanitize_text_field((string)$isViewerOnly);
388 +
389 + if ($boardId <= 0 || $memberId <= 0) {
390 + return null;
391 + }
392 +
378 393 $board = Board::find($boardId);
394 + $boardMember = User::find($memberId);
379 395
380 - if (!$board) {
381 - return false;
396 + if (!$board || !$boardMember) {
397 + return null;
382 398 }
383 399 $isAlreadyMember = $this->isAlreadyMember($boardId, $memberId);
384 400 if($isAlreadyMember) {
385 401 return false;
@@ -399,9 +415,8 @@
399 415 'settings' => maybe_serialize($settings),
400 416 'preferences' => maybe_serialize(Constant::BOARD_NOTIFICATION_TYPES)
401 417 ]
402 418 );
403 - $boardMember = User::find($memberId);
404 419 if(!$isViewerOnly) {
405 420 do_action('fluent_boards/board_member_added', $boardId, $boardMember);
406 421 } else {
407 422 do_action('fluent_boards/board_viewer_added', $boardId, $boardMember);
@@ -522,20 +537,31 @@
522 537
523 538 /**
524 539 * Change or clear the board background.
525 540 *
526 - * @param mixed $backgroundData
541 + * Image attachments must belong to the target board and use the board
542 + * background attachment type before their identifiers can be persisted.
543 + *
544 + * @param array $backgroundData
545 + * @param int $board_id
527 546 * @return array|string
547 + * @throws \Exception
528 548 */
529 549 public function setBoardBackground($backgroundData, $board_id)
530 550 {
531 - $board = Board::find($board_id);
551 + $boardId = absint($board_id);
552 + $board = Board::find($boardId);
553 +
554 + if (!$board) {
555 + throw new \Exception(esc_html__('Board not found.', 'fluent-boards'));
556 + }
557 +
532 558 $oldBackground = $board->background;
533 559
534 560 if (!empty($backgroundData['reset'])) {
535 561 $board->background = '';
536 562 $board->save();
537 - do_action('fluent_boards/board_background_updated', $board_id, $oldBackground);
563 + do_action('fluent_boards/board_background_updated', $boardId, $oldBackground);
538 564
539 565 return $board->background;
540 566 }
541 567
@@ -543,26 +569,34 @@
543 569 if (!is_array($background)) {
544 570 $background = [];
545 571 }
546 572
547 - // if board background has color
548 - if (isset($backgroundData['color'])) {
573 + // Resolve image metadata from the board-owned attachment, never from the client URL.
574 + if (isset($backgroundData['image_url'])) {
575 + $attachmentId = absint($backgroundData['id'] ?? 0);
576 + $attachment = Attachment::where('id', $attachmentId)
577 + ->where('object_id', $boardId)
578 + ->where('object_type', Constant::BOARD_BACKGROUND_IMAGE)
579 + ->first();
580 +
581 + if (!$attachment) {
582 + throw new \Exception(esc_html__('Background image not found.', 'fluent-boards'));
583 + }
584 +
585 + $background['id'] = (int) $attachment->id;
586 + $background['image_url'] = (new CommentService())->createPublicUrl($attachment, $boardId);
587 + $background['is_image'] = true;
588 + $background['color'] = null;
589 + } elseif (isset($backgroundData['color'])) {
590 + $background['id'] = $backgroundData['id'];
549 591 $background['color'] = $backgroundData['color'];
550 592 $background['image_url'] = null;
551 593 $background['is_image'] = false;
552 594 }
553 595
554 - // if board background has image
555 - if (isset($backgroundData['image_url'])) {
556 - $background['image_url'] = $backgroundData['image_url'];
557 - $background['is_image'] = true;
558 - $background['color'] = null;
559 - }
560 - $background['id'] = $backgroundData['id'];
561 -
562 596 $board->background = $background;
563 597 $board->save();
564 - do_action('fluent_boards/board_background_updated', $board_id, $oldBackground);
598 + do_action('fluent_boards/board_background_updated', $boardId, $oldBackground);
565 599
566 600 return $board->background;
567 601 }
568 602
@@ -775,9 +809,15 @@
775 809
776 810 $this->updateRecentBoardCheckMeta();
777 811 }
778 812
779 - return Board::whereIn('id', $recentBoardIds)->excludeTemplates()->withCount('completedTasks')->with(['stages', 'users'])->get();
813 + return Board::whereIn('id', $recentBoardIds)
814 + ->whereNull('archived_at')
815 + ->excludeTemplates()
816 + ->availableInCurrentInstall()
817 + ->withCount('completedTasks')
818 + ->with(['stages', 'users'])
819 + ->get();
780 820 }
781 821
782 822 public function getRecentBoardCheckMeta($userId = null){
783 823 if (!$userId) {
@@ -904,11 +944,35 @@
904 944 ->where('key', Constant::BOARD_INVITATION)
905 945 ->get();
906 946 }
907 947
908 - public function deleteInvitation($invitationId)
948 + /**
949 + * Delete an invitation only when it belongs to the supplied board.
950 + *
951 + * The optional second argument lets older Pro releases receive a controlled
952 + * error instead of reporting a successful deletion that never happened.
953 + */
954 + public function deleteInvitation($boardId, $invitationId = null)
909 955 {
910 - Meta::findOrFail($invitationId)->delete();
956 + if ($invitationId === null) {
957 + throw new \Exception(
958 + __('A board ID is required to delete an invitation.', 'fluent-boards')
959 + );
960 + }
961 +
962 + $boardId = intval($boardId);
963 + $invitationId = intval($invitationId);
964 +
965 + if ($boardId <= 0 || $invitationId <= 0) {
966 + return false;
967 + }
968 +
969 + return (bool) Meta::query()
970 + ->where('id', $invitationId)
971 + ->where('object_id', $boardId)
972 + ->where('object_type', Constant::OBJECT_TYPE_BOARD)
973 + ->where('key', Constant::BOARD_INVITATION)
974 + ->delete();
911 975 }
912 976
913 977 public function hasDataChanged($boardId, $includeArchived = false, $since = null)
914 978 {
@@ -1220,13 +1284,11 @@
1220 1284 * @return array{all: int, pinned: int, archived: int}
1221 1285 */
1222 1286 public function getBoardCounts($userId)
1223 1287 {
1224 - $baseQuery = Board::byAccessUser($userId)->excludeTemplates();
1225 -
1226 - if (!defined('FLUENT_ROADMAP')) {
1227 - $baseQuery = $baseQuery->where('type', 'to-do');
1228 - }
1288 + $baseQuery = Board::byAccessUser($userId)
1289 + ->excludeTemplates()
1290 + ->availableInCurrentInstall();
1229 1291
1230 1292 $counts = [
1231 1293 'all' => (clone $baseQuery)->whereNull('archived_at')->count(),
1232 1294 'pinned' => 0,