PluginProbe
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration / 1.91.6
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration v1.91.6
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
fluent-boards / app / Services / Helper.php

Helper.php in FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration 1.91.6, at app/Services/Helper.php

567 lines 17.4 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\Services;
4
5 use FluentBoards\App\Models\Activity;
6 use FluentBoards\App\Models\Stage;
7 use FluentBoards\App\Models\Webhook;
8 use FluentBoards\Framework\Support\Arr;
9 use FluentBoards\Framework\Support\Str;
10 use FluentBoards\App\Models\Board;
11 use FluentBoards\App\Services\Parsedown;
12 use FluentBoards\App\Services\PermissionManager;
13
14 class Helper
15 {
16 public static function snake_case($string)
17 {
18 return strtolower(preg_replace('/(?<!^)[A-Z]/', '_$0', $string));
19 }
20
21 public static function slugify($text, $id = '', $length = 20)
22 {
23 $text = substr($text, 0, $length); // limiting to max 20 chars
24 $text = Str::slug($text);
25 if ($id) {
26 $text = $id . '-' . $text;
27 }
28
29 return $text;
30 }
31
32 public static function loadView($template, $data)
33 {
34 extract($data, EXTR_OVERWRITE);
35
36 $template = sanitize_file_name($template);
37
38 $template = str_replace('.', DIRECTORY_SEPARATOR, $template);
39
40 ob_start();
41 include FLUENT_BOARDS_PLUGIN_PATH . 'app/Views/' . $template . '.php';
42
43 return ob_get_clean();
44 }
45
46 private static function sanitizeData($data, $fieldMaps)
47 {
48 foreach ($data as $key => $value) {
49 if ($value && isset($fieldMaps[$key]) && !is_array($value)) {
50 $data[$key] = call_user_func($fieldMaps[$key], $value);
51 }
52 }
53
54 return $data;
55 }
56
57 public static function sanitizeTask($data)
58 {
59 $fieldMaps = [
60 'title' => 'sanitize_text_field',
61 'board_id' => 'intval',
62 'parent_id' => 'intval',
63 'crm_contact_id' => 'intval',
64 'type' => 'sanitize_text_field',
65 'stage' => 'sanitize_text_field',
66 'reminder_type' => 'sanitize_text_field',
67 'priority' => 'sanitize_text_field',
68 'lead_value' => 'doubleval',
69 'remind_at' => 'sanitize_text_field',
70 'scope' => 'sanitize_text_field',
71 'source' => 'sanitize_text_field',
72 'description' => 'wp_kses_post',
73 'due_date' => 'sanitize_text_field',
74 'start_at' => 'sanitize_text_field',
75 'log_minutes' => 'sanitize_text_field',
76 'last_completed' => 'sanitize_text_field',
77 'assignees' => 'intval',
78 'is_archived' => 'intval',
79 'previous_stage' => 'sanitize_text_field',
80 'new_stage' => 'sanitize_text_field',
81 'new_index' => 'intval',
82 'old_index' => 'intval',
83 'new_board_id' => 'intval',
84 'position' => 'intval'
85
86 ];
87
88 return self::sanitizeData($data, $fieldMaps);
89 }
90
91 public static function sanitizeBoard($data)
92 {
93 $fieldMaps = [
94 'board_id' => 'intval',
95 'title' => 'sanitize_text_field',
96 'parent_id' => 'intval',
97 'type' => 'sanitize_text_field',
98 'description' => 'wp_kses_post',
99 'currency' => 'sanitize_text_field',
100 'image_url' => 'sanitize_url',
101 'is_auth_require' => 'intval',
102 'crm_contact_id' => 'intval',
103 'id' => 'sanitize_text_field',
104 'is_image' => 'rest_sanitize_boolean',
105 'color' => 'sanitize_text_field', // sanitize_hex_color doesn't work when color code is greater than 6 characters
106 'created_by' => 'intval',
107 ];
108
109 return self::sanitizeData($data, $fieldMaps);
110 }
111
112 public static function sanitizeStage($data)
113 {
114 $fieldMaps = [
115 'title' => 'sanitize_text_field',
116 'slug' => 'sanitize_text_field',
117 'type' => 'sanitize_text_field',
118 'status' => 'sanitize_text_field',
119 ];
120
121 return self::sanitizeData($data, $fieldMaps);
122 }
123
124 public static function sanitizeComment($data)
125 {
126 $fieldMaps = [
127 'description' => 'wp_kses_post',
128 'created_by' => 'intval',
129 'task_id' => 'intval',
130 'type' => 'sanitize_text_field',
131 ];
132
133 return self::sanitizeData($data, $fieldMaps);
134 }
135
136 public static function sanitizeLabel($data)
137 {
138 $fieldMaps = [
139 'bg_color' => 'sanitize_text_field',
140 'color' => 'sanitize_text_field',
141 'label' => 'sanitize_text_field',
142 'boardId' => 'intval',
143 'task_id' => 'intval',
144 'meta_value' => 'intval',
145 ];
146
147 return self::sanitizeData($data, $fieldMaps);
148 }
149
150 public static function sanitizeSubtask($data)
151 {
152 $fieldMaps = [
153 'title' => 'sanitize_text_field',
154 'stage' => 'sanitize_text_field',
155 'newPosition' => 'intval',
156 'priority' => 'sanitize_text_field',
157 'type' => 'sanitize_text_field',
158 'board_id' => 'intval',
159 'created_by' => 'intval',
160 'due_date' => 'sanitize_text_field',
161 ];
162
163 return self::sanitizeData($data, $fieldMaps);
164 }
165
166 public static function createActivity($data)
167 {
168 return Activity::create($data);
169 }
170
171 public static function sanitizeTaskMeta($data)
172 {
173 $fieldMaps = [
174 'title' => 'sanitize_text_field',
175 'url' => 'sanitize_url',
176
177 ];
178
179 return self::sanitizeData($data, $fieldMaps);
180 }
181
182 public static function getFormattedStagesByBoardId($boardId)
183 {
184 if (!$boardId) {
185 return [];
186 }
187
188 $board = Board::findOrFail($boardId);
189
190 $stages = $board->stages()->get();
191 // return static::formateStage($stages);
192 return $stages;
193 }
194
195 public static function getStagesByBoardId($boardId)
196 {
197 if (!$boardId) {
198 return [];
199 }
200
201 $board = Board::findOrFail($boardId);
202
203 $stages = $board->stages()->get();
204 return static::formateStage($stages);
205 // return $stages;
206 }
207
208 public static function formateStage($stages)
209 {
210 if (!$stages) return [];
211
212 $formattedStages = [];
213 foreach ($stages as $stage) {
214 $boardName = $stage->board->title;
215 $formattedStages[] = [
216 'id' => strval($stage->id),
217 'title' => $boardName . ' - ' . $stage->title
218 ];
219 }
220 return $formattedStages;
221 }
222
223 public static function getIdTitleArray($data)
224 {
225 $array = [];
226 foreach ($data as $item) {
227 $array[] = [
228 'id' => $item->id,
229 'title' => $item->title
230 ];
231 }
232 return $array;
233 }
234
235 // get Task Url by task id and board id
236 public static function getTaskUrl($taskId, $boardId): string
237 {
238 if (!$taskId || !$boardId) {
239 return '';
240 }
241 return fluent_boards_page_url() . 'boards/' . $boardId . '/tasks/' . $taskId;
242 }
243
244 public static function getTaskUrlByTask($task): string
245 {
246 if (!$task) {
247 return '';
248 }
249 return fluent_boards_page_url() . 'boards/' . $task->board_id . '/tasks/' . $task->id;
250 }
251
252 public static function getBoardUrl($boardId): string
253 {
254 if (!$boardId) {
255 return '';
256 }
257 return fluent_boards_page_url() . 'boards/' . $boardId;
258 }
259
260 public static function crm_contact($id)
261 {
262 if (!defined('FLUENTCRM')) {
263 return '';
264 }
265
266 $contact = \FluentCrm\App\Models\Subscriber::with(['tags', 'lists'])->find($id);
267
268 if (!$contact) {
269 return null;
270 }
271
272 return [
273 'id' => $contact->id,
274 'email' => $contact->email,
275 'first_name' => $contact->first_name,
276 'last_name' => $contact->last_name,
277 'full_name' => $contact->full_name,
278 'avatar' => $contact->avatar,
279 'photo' => $contact->photo,
280 'status' => $contact->status,
281 'contact_type' => $contact->contact_type,
282 'last_activity' => $contact->last_activity,
283 'life_time_value' => $contact->life_time_value,
284 'total_points' => $contact->total_points,
285 'user_id' => $contact->user_id,
286 'created_at' => $contact->created_at,
287 'tags' => Helper::getIdTitleArray($contact->tags),
288 'lists' => Helper::getIdTitleArray($contact->lists)
289
290 ];
291
292 }
293
294 public static function getStagesByBoardGroup()
295 {
296 $boards = self::getBoards();
297
298 $groups = [];
299 foreach ($boards as $board) {
300 $groups[] = [
301 'title' => $board->title,
302 'slug' => 'aaa' . '_' . $board->id,
303 'options' => self::getStagesByBoardId($board->id)
304 ];
305 }
306 return $groups;
307 }
308
309 public static function getBoards()
310 {
311 return Board::orderBy('created_at', 'ASC')->get();
312 }
313
314 public static function getStage($stageId)
315 {
316 return Stage::findOrFail($stageId);
317 }
318
319 public static function getBoardByStageId($stageId)
320 {
321 $stage = self::getStage($stageId);
322 return $stage->board;
323 }
324
325 public static function sanitizeUserCollections($users)
326 {
327 if (empty($users) || !is_array($users)) {
328 return $users;
329 }
330
331 foreach ($users as $key => $user) {
332 if (is_object($user) && isset($user->pivot)) {
333 $settings = maybe_unserialize($user->pivot->settings);
334 $user->role = Arr::get($settings, 'is_admin')
335 ? 'Admin'
336 : (Arr::has($settings, 'is_viewer_only') && Arr::get($settings, 'is_viewer_only')
337 ? 'Viewer'
338 : 'Member');
339 }
340 }
341
342 if (current_user_can('list_users')) {
343 return $users;
344 }
345
346 if ($users) {
347 $users->makeHidden(['user_email', 'user_nicename', 'user_registered', 'user_url', 'user_status']);
348 }
349
350 return $users;
351 }
352
353 public static function sanitizeUsersArray($users, $boardId = null)
354 {
355 if (current_user_can('list_users')) {
356 return $users;
357 }
358
359 $sanitizedUsers = [];
360
361 if(!PermissionManager::isBoardManager($boardId)) //Todo: may create permission security issue, will be modified later
362 {
363 $currentUser = wp_get_current_user();
364 if($currentUser && isset($currentUser->user_email)){
365 $currentUserEmail = $currentUser->user_email;
366 }
367 foreach ($users as $user) {
368
369 if($user['email'] === $currentUserEmail){
370 $sanitizedUsers[] = $user;
371 continue;
372 }
373
374 if (isset($user['email'])) {
375 $user['email'] = self::obfuscateEmail($user['email']);
376 }
377 if (isset($user['user_email'])) {
378 $user['user_email'] = self::obfuscateEmail($user['user_email']);
379 }
380
381 $sanitizedUsers[] = $user;
382 }
383 } else {
384 foreach ($users as $user) {
385 $sanitizedUsers[] = $user;
386 }
387 }
388
389 return $sanitizedUsers;
390 }
391
392 public static function obfuscateEmail($email)
393 {
394 if (!is_string($email) || filter_var($email, FILTER_VALIDATE_EMAIL) === false) {
395 return $email; // Not a valid email, return as is
396 }
397
398 list($name, $domain) = explode('@', $email, 2);
399
400 // Local part: show first 3 chars, then fixed ****
401 $visibleLocal = substr($name, 0, 3);
402 $maskedLocal = $visibleLocal . '****';
403
404 // Domain: mask the main label to **** + last 2 chars, keep rest (TLDs) intact
405 $domainParts = explode('.', $domain);
406 $mainLabel = $domainParts[0] ?? '';
407 $tail = strlen($mainLabel) >= 2 ? substr($mainLabel, -2) : $mainLabel;
408 $domainParts[0] = '****' . $tail; // e.g., example.com -> ****le.com
409 $maskedDomain = implode('.', $domainParts);
410
411 return $maskedLocal . '@' . $maskedDomain;
412 }
413
414 public static function getPriorityOptions()
415 {
416 return [
417 [
418 'id' => 'low',
419 'title' => 'Low'
420 ],
421 [
422 'id' => 'medium',
423 'title' => 'Medium'
424 ],
425 [
426 'id' => 'high',
427 'title' => 'High'
428 ],
429 ];
430 }
431
432 public static function dueDateConversion($due_time, $unit)
433 {
434 if($due_time <= 0) {
435 return null;
436 }
437 $currentTime = current_time('mysql');
438 $readyString = '+' . $due_time . ' ' . $unit;
439 return gmdate('Y-m-d H:i:s',strtotime($readyString,strtotime($currentTime)));
440 }
441
442 public static function searchWordPressUsers($searchQuery, $limit = 20)
443 {
444 $search = sanitize_text_field($searchQuery);
445
446 // Search by user login, email, and nicename
447 $args = array(
448 'role' => '',
449 'search' => '*' . $search . '*',
450 'number' => $limit,
451 );
452
453 // Get users by login, email, and nicename
454 $user_query = new \WP_User_Query($args);
455 $users_by_login = $user_query->get_results();
456
457 // Search by first name and last name
458 $meta_query_args = array(
459 'relation' => 'OR',
460 array(
461 'key' => 'first_name',
462 'value' => $search,
463 'compare' => 'LIKE',
464 ),
465 array(
466 'key' => 'last_name',
467 'value' => $search,
468 'compare' => 'LIKE',
469 ),
470 );
471
472 $meta_query = array(
473 'role' => '',
474 'meta_query' => $meta_query_args,
475 'number' => $limit,
476 );
477
478 // Get users by first name and last name
479 $users_by_meta = get_users($meta_query);
480
481 // Merge and remove duplicates
482 $users = array_merge($users_by_login, $users_by_meta);
483 $users = array_unique($users, SORT_REGULAR);
484
485 return $users;
486
487 }
488
489 public static function sanitizeTaskAttachment($data)
490 {
491 $fieldMaps = [
492 'title' => 'sanitize_text_field',
493 'url' => 'sanitize_url',
494 ];
495
496 return self::sanitizeData($data, $fieldMaps);
497 }
498
499 public static function sanitizeTaskRepeatData($data)
500 {
501 $fieldMaps = [
502 'create_new' => 'intval',
503 'repeat_in' => 'intval',
504 'repeat_type' => 'sanitize_text_field',
505 'repeat_when_complete' => 'intval',
506 'selected_month' => 'sanitize_text_field',
507 'board_id' => 'intval',
508 'time' => 'sanitize_text_field',
509 'time_zone' => 'sanitize_text_field',
510 'next_repeat_date' => 'sanitize_text_field',
511 'repeat_in_month_type' => 'sanitize_text_field',
512 ];
513
514 return self::sanitizeData($data, $fieldMaps);
515 }
516
517 public static function sanitizeTaskForWebHook($data)
518 {
519 $fieldMaps = [
520 'title' => 'sanitize_text_field',
521 'board_id' => 'intval',
522 'parent_id' => 'intval',
523 'crm_contact_id' => 'intval',
524 'type' => 'sanitize_text_field',
525 'stage' => 'sanitize_text_field',
526 'reminder_type' => 'sanitize_text_field',
527 'priority' => 'sanitize_text_field',
528 'lead_value' => 'doubleval',
529 'remind_at' => 'sanitize_text_field',
530 'scope' => 'sanitize_text_field',
531 'source' => 'sanitize_text_field',
532 'description' => 'wp_kses_post',
533 'due_date' => 'sanitize_text_field',
534 'start_at' => 'sanitize_text_field',
535 'log_minutes' => 'sanitize_text_field',
536 'last_completed' => 'sanitize_text_field',
537 'is_archived' => 'intval',
538 'previous_stage' => 'sanitize_text_field',
539 'new_stage' => 'sanitize_text_field',
540 'new_index' => 'intval',
541 'old_index' => 'intval',
542 'new_board_id' => 'intval',
543 'position' => 'intval'
544
545 ];
546
547 return self::sanitizeData($data, $fieldMaps);
548 }
549
550
551 public static function taskReminderTypes()
552 {
553 $allowedTypes = [
554 '30_minutes_before' => __('30 minutes before', 'fluent-boards'),
555 '1_hour_before' => __('1 hour before', 'fluent-boards'),
556 '2_hours_before' => __('2 hours before', 'fluent-boards'),
557 '1_day_before' => __('1 day before', 'fluent-boards'),
558 '2_days_before' => __('2 days before', 'fluent-boards'),
559 '1_week_before' => __('1 week before', 'fluent-boards'),
560 ];
561
562 $allowedTypes = apply_filters('fluent_boards/task_reminder_types', $allowedTypes);
563
564 return $allowedTypes;
565 }
566 }
567