PluginProbe
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration / 2.2.0
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration v2.2.0
2.2.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 All 43 releases
← All changes | app/Services/Helper.php +94 -11 1.95.3 → 2.2.0 View file →
@@ -128,9 +128,9 @@
128 128 'remind_at' => 'sanitize_text_field',
129 129 'scope' => 'sanitize_text_field',
130 130 'source' => 'sanitize_text_field',
131 131 'source_id' => 'sanitize_text_field',
132 - 'description' => 'wp_kses_post',
132 + 'description' => 'fluent_boards_sanitize_description',
133 133 'due_date' => 'sanitize_text_field',
134 134 'start_at' => 'sanitize_text_field',
135 135 'log_minutes' => 'sanitize_text_field',
136 136 'last_completed' => 'sanitize_text_field',
@@ -154,9 +154,9 @@
154 154 'board_id' => 'intval',
155 155 'title' => 'sanitize_text_field',
156 156 'parent_id' => 'intval',
157 157 'type' => 'sanitize_text_field',
158 - 'description' => 'wp_kses_post',
158 + 'description' => 'fluent_boards_sanitize_description',
159 159 'currency' => 'sanitize_text_field',
160 160 'image_url' => 'sanitize_url',
161 161 'is_auth_require' => 'intval',
162 162 'crm_contact_id' => 'intval',
@@ -162,8 +162,9 @@
162 162 'crm_contact_id' => 'intval',
163 163 'id' => 'sanitize_text_field',
164 164 'is_image' => 'rest_sanitize_boolean',
165 165 'color' => 'sanitize_text_field', // sanitize_hex_color doesn't work when color code is greater than 6 characters
166 + 'reset' => 'rest_sanitize_boolean',
166 167 'created_by' => 'intval',
167 168 ];
168 169
169 170 return self::sanitizeData($data, $fieldMaps);
@@ -197,8 +198,9 @@
197 198 {
198 199 $fieldMaps = [
199 200 'bg_color' => 'sanitize_text_field',
200 201 'color' => 'sanitize_text_field',
202 + 'color_preset' => 'sanitize_key',
201 203 'label' => 'sanitize_text_field',
202 204 'boardId' => 'intval',
203 205 'task_id' => 'intval',
204 206 'meta_value' => 'intval',
@@ -214,18 +216,48 @@
214 216 'stage' => 'sanitize_text_field',
215 217 'newPosition' => 'intval',
216 218 'priority' => 'sanitize_text_field',
217 219 'type' => 'sanitize_text_field',
220 + 'description' => 'fluent_boards_sanitize_description',
221 + 'group_id' => 'intval',
218 222 'board_id' => 'intval',
219 223 'created_by' => 'intval',
220 224 'due_date' => 'sanitize_text_field',
225 + 'due_at' => 'sanitize_text_field',
226 + 'started_at' => 'sanitize_text_field',
227 + 'reminder_type' => 'sanitize_text_field',
228 + 'remind_at' => 'sanitize_text_field',
229 + 'add_to_top' => 'rest_sanitize_boolean',
221 230 ];
222 231
223 - return self::sanitizeData($data, $fieldMaps);
232 + $data = self::sanitizeData($data, $fieldMaps);
233 +
234 + if (!empty($data['assignees']) && is_array($data['assignees'])) {
235 + $data['assignees'] = array_slice(array_filter(array_map('intval', $data['assignees'])), 0, 1);
236 + }
237 +
238 + if (!empty($data['labels']) && is_array($data['labels'])) {
239 + $data['labels'] = array_filter(array_map('intval', $data['labels']));
240 + }
241 +
242 + return $data;
224 243 }
225 244
245 + /** Store full custom-field messages in LONGTEXT while keeping legacy VARCHAR columns bounded. */
226 246 public static function createActivity($data)
227 247 {
248 + if (!empty($data['settings']['custom_field_id'])) {
249 + $payload = [];
250 + foreach (['column', 'old_value', 'new_value', 'description'] as $key) {
251 + $payload[$key] = $data[$key] ?? null;
252 + }
253 + $data['settings']['custom_field_activity_payload'] = true;
254 + $data['description'] = wp_json_encode($payload);
255 + $data['column'] = Constant::ACTIVITY_CUSTOM_FIELD;
256 + $data['old_value'] = null;
257 + $data['new_value'] = null;
258 + }
259 +
228 260 return Activity::create($data);
229 261 }
230 262
231 263 public static function sanitizeTaskMeta($data)
@@ -316,8 +348,9 @@
316 348 }
317 349 return fluent_boards_page_url() . 'boards/' . $boardId;
318 350 }
319 351
352 + /** Format a CRM contact, avoiding a database lookup for unassociated tasks. */
320 353 public static function crm_contact($id)
321 354 {
322 355 if (!defined('FLUENTCRM')) {
323 356 return '';
@@ -322,8 +355,12 @@
322 355 if (!defined('FLUENTCRM')) {
323 356 return '';
324 357 }
325 358
359 + if (!$id) {
360 + return null;
361 + }
362 +
326 363 $contact = \FluentCrm\App\Models\Subscriber::with(['tags', 'lists'])->find($id);
327 364
328 365 if (!$contact) {
329 366 return null;
@@ -416,9 +453,10 @@
416 453
417 454 return $users;
418 455 }
419 456
420 - public static function sanitizeUsersArray($users, $boardId = null)
457 + // Callers formatting multiple lists may supply a resolved board-manager result.
458 + public static function sanitizeUsersArray($users, $boardId = null, $isBoardManager = null)
421 459 {
422 460 if (current_user_can('list_users')) {
423 461 return $users;
424 462 }
@@ -424,9 +462,9 @@
424 462 }
425 463
426 464 $sanitizedUsers = [];
427 465
428 - if(!PermissionManager::isBoardManager($boardId)) //Todo: may create permission security issue, will be modified later
466 + if (!($isBoardManager ?? PermissionManager::isBoardManager($boardId)))
429 467 {
430 468 $currentUser = wp_get_current_user();
431 469 if($currentUser && isset($currentUser->user_email)){
432 470 $currentUserEmail = $currentUser->user_email;
@@ -481,18 +519,26 @@
481 519 public static function getPriorityOptions()
482 520 {
483 521 return [
484 522 [
485 - 'id' => 'low',
486 - 'title' => 'Low'
523 + 'id' => '',
524 + 'title' => 'No priority'
487 525 ],
488 526 [
527 + 'id' => 'urgent',
528 + 'title' => 'Urgent'
529 + ],
530 + [
531 + 'id' => 'high',
532 + 'title' => 'High'
533 + ],
534 + [
489 535 'id' => 'medium',
490 536 'title' => 'Medium'
491 537 ],
492 538 [
493 - 'id' => 'high',
494 - 'title' => 'High'
539 + 'id' => 'low',
540 + 'title' => 'Low'
495 541 ],
496 542 ];
497 543 }
498 544
@@ -570,8 +616,9 @@
570 616 'repeat_in' => 'intval',
571 617 'repeat_type' => 'sanitize_text_field',
572 618 'repeat_when_complete' => 'intval',
573 619 'selected_month' => 'sanitize_text_field',
620 + 'selected_stage' => 'intval',
574 621 'board_id' => 'intval',
575 622 'time' => 'sanitize_text_field',
576 623 'time_zone' => 'sanitize_text_field',
577 624 'next_repeat_date' => 'sanitize_text_field',
@@ -580,8 +627,27 @@
580 627
581 628 return self::sanitizeData($data, $fieldMaps);
582 629 }
583 630
631 + /**
632 + * Sanitize the author snapshot supplied by an external task integration.
633 + *
634 + * @param mixed $author
635 + * @return array
636 + */
637 + private static function sanitizeExternalTaskAuthor($author)
638 + {
639 + if (!is_array($author)) {
640 + return [];
641 + }
642 +
643 + return array_filter([
644 + 'name' => sanitize_text_field($author['name'] ?? ''),
645 + 'email' => sanitize_email($author['email'] ?? ''),
646 + 'photo' => esc_url_raw($author['photo'] ?? ''),
647 + ]);
648 + }
649 +
584 650 public static function sanitizeTaskForWebHook($data)
585 651 {
586 652 $fieldMaps = [
587 653 'title' => 'sanitize_text_field',
@@ -595,9 +661,10 @@
595 661 'lead_value' => 'doubleval',
596 662 'remind_at' => 'sanitize_text_field',
597 663 'scope' => 'sanitize_text_field',
598 664 'source' => 'sanitize_text_field',
599 - 'description' => 'wp_kses_post',
665 + 'source_id' => 'sanitize_text_field',
666 + 'description' => 'fluent_boards_sanitize_description',
600 667 'due_date' => 'sanitize_text_field',
601 668 'start_at' => 'sanitize_text_field',
602 669 'log_minutes' => 'sanitize_text_field',
603 670 'last_completed' => 'sanitize_text_field',
@@ -610,9 +677,19 @@
610 677 'position' => 'intval'
611 678
612 679 ];
613 680
614 - return self::sanitizeData($data, $fieldMaps);
681 + $data = self::sanitizeData($data, $fieldMaps);
682 +
683 + if (isset($data['settings']) && is_array($data['settings']) && isset($data['settings']['author'])) {
684 + $data['settings'] = [
685 + 'author' => self::sanitizeExternalTaskAuthor($data['settings']['author']),
686 + ];
687 + } else {
688 + unset($data['settings']);
689 + }
690 +
691 + return $data;
615 692 }
616 693
617 694
618 695 public static function taskReminderTypes()
@@ -647,11 +724,13 @@
647 724 'deleted' => __('deleted', 'fluent-boards'),
648 725 'archived' => __('archived', 'fluent-boards'),
649 726 'restored' => __('restored', 'fluent-boards'),
650 727 'set' => __('set', 'fluent-boards'),
728 + 'moved' => __('moved', 'fluent-boards'),
651 729 ];
652 730
653 731 $columnTranslations = [
732 + Constant::ACTIVITY_CUSTOM_FIELD => __('custom field', 'fluent-boards'),
654 733 'task' => __('task', 'fluent-boards'),
655 734 'description' => __('description', 'fluent-boards'),
656 735 'board' => __('board', 'fluent-boards'),
657 736 'assignee' => __('assignee', 'fluent-boards'),
@@ -668,11 +747,15 @@
668 747 'the associate email' => __('the associate email', 'fluent-boards'),
669 748 'attachment' => __('attachment', 'fluent-boards'),
670 749 'repeat task' => __('repeat task', 'fluent-boards'),
671 750 'Repeat Task' => __('Repeat Task', 'fluent-boards'),
751 + 'tasks' => __('tasks', 'fluent-boards'),
672 752 ];
673 753
674 754 foreach ($activities as $activity) {
755 + $activity->action_key = $activity->action;
756 + $activity->column_key = $activity->column;
757 +
675 758 if (isset($actionTranslations[$activity->action])) {
676 759 $activity->action = $actionTranslations[$activity->action];
677 760 }
678 761 if (isset($columnTranslations[$activity->column])) {