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 / Hooks / Handlers / AdminMenuHandler.php

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

605 lines 22.2 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\Hooks\Handlers;
4
5 use FluentBoards\App\App;
6 use FluentBoards\App\Models\Board;
7 use FluentBoards\App\Models\Meta;
8 use FluentBoards\App\Models\Relation;
9 use FluentBoards\App\Services\Constant;
10 use FluentBoards\App\Services\Helper;
11 use FluentBoards\App\Services\TransStrings;
12 use FluentBoards\Framework\Support\Arr;
13 use FluentBoards\Framework\Support\Collection;
14 use FluentBoards\App\Services\PermissionManager;
15 use FluentBoards\Framework\Support\DateTime;
16
17 class AdminMenuHandler
18 {
19
20 public function register()
21 {
22 add_action('admin_menu', [$this, 'add'], 11);
23
24 add_filter('fluent_crm/core_menu_items', function ($items) {
25 if (PermissionManager::userHasAnyBoardAccess()) {
26 $items['fluent-boards'] = [
27 'key' => 'fluent-boards',
28 'label' => __('Boards', 'fluent-boards'),
29 'permalink' => admin_url('admin.php?page=fluent-boards#/')
30 ];
31 }
32 return $items;
33 });
34
35 add_action('admin_enqueue_scripts', function () {
36 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Checking admin page context for asset enqueuing, no data modification
37 if (!isset($_REQUEST['page']) || $_REQUEST['page'] !== 'fluent-boards') {
38 return;
39 }
40
41 $this->enqueueAssets();
42 });
43
44 add_filter('fluent_crm/sidebar_core_menu_items', function($menuItems, $permissions) {
45 $settings = fluent_boards_get_pref_settings();
46 if (Arr::get($settings, 'menu_settings.in_fluent_crm') === 'yes') {
47 $menuItems[] = [
48 'key' => 'fluent-boards',
49 'page_title' => __('Fluent Boards', 'fluent-boards'),
50 'menu_title' => __('Fluent Boards', 'fluent-boards'),
51 'capability' => 'manage_options',
52 'uri' => admin_url('admin.php?page=fluent-boards')
53 ];
54 }
55 return $menuItems;
56 }, 10, 2);
57 }
58
59 public function add()
60 {
61 if (!PermissionManager::userHasAnyBoardAccess()) {
62 return;
63 }
64
65 $user = get_user_by('ID', get_current_user_id());
66
67 if (current_user_can('manage_options')) {
68 $capability = 'manage_options';
69 } else {
70 $roles = array_values((array)$user->roles);
71 $capability = Arr::get($roles, 0);
72 }
73
74 $settings = fluent_boards_get_pref_settings();
75
76 if (defined('FLUENTCRM') && \FluentCrm\App\Services\PermissionManager::currentUserPermissions() && Arr::get($settings, 'menu_settings.in_fluent_crm') === 'yes') {
77 add_submenu_page(
78 'fluentcrm-admin', //$parent_slug
79 __('Fluent Boards', 'fluent-boards'), //$page_title
80 __('Fluent Boards', 'fluent-boards'), //$menu_title
81 $capability,
82 'fluent-boards', //$menu_slug
83 [$this, 'render'],
84 );
85 return;
86 }
87
88 add_menu_page(
89 __('Fluent Boards', 'fluent-boards'),
90 __('Fluent Boards', 'fluent-boards'),
91 $capability,
92 'fluent-boards',
93 [$this, 'render'],
94 $this->getMenuIcon(),
95 Arr::get($settings, 'menu_settings.menu_position', 3)
96 );
97
98 add_submenu_page(
99 'fluent-boards',
100 __('Dashboard', 'fluent-boards'),
101 __('Dashboard', 'fluent-boards'),
102 $capability,
103 'fluent-boards',
104 [$this, 'render']
105 );
106
107 add_submenu_page(
108 'fluent-boards',
109 __('Boards', 'fluent-boards'),
110 __('Boards', 'fluent-boards'),
111 $capability,
112 'fluent-boards#/boards',
113 [$this, 'render']
114 );
115
116 do_action('fluent_boards/after_core_menu_items', $permissions = [], $isAdmin = true);
117
118 add_submenu_page(
119 'fluent-boards',
120 __('Reports', 'fluent-boards'),
121 __('Reports', 'fluent-boards'),
122 $capability,
123 'fluent-boards#/reports',
124 [$this, 'render']
125 );
126
127 add_submenu_page(
128 'fluent-boards',
129 __('Settings', 'fluent-boards'),
130 __('Settings', 'fluent-boards'),
131 'manage_options',
132 'fluent-boards#/settings/members-role',
133 [$this, 'render']
134 );
135 }
136
137 public function render()
138 {
139 $this->changeFooter();
140
141 $config = App::getInstance('config');
142
143 $name = $config->get('app.name');
144 $app = App::getInstance();
145 $assets = $app['url.assets'];
146 $slug = $config->get('app.slug');
147 $baseUrl = fluent_boards_page_url();
148
149 do_action('fluent_boards/rendering_app');
150
151 // For subtask sync
152 UpdateHandler::maybeSubtaskGroupSync();
153
154 App::make('view')->render('admin.menu', [
155 'name' => $name,
156 'slug' => $slug,
157 'menuItems' => $this->getMenuItems($app),
158 'baseUrl' => $baseUrl,
159 'logo' => apply_filters('fluent_boards/app_logo', $assets . 'images/logo.svg'),
160 'icon' => apply_filters('fluent_boards/app_icon', $assets . 'images/icon.svg'),
161 'is_new' => Board::count() == 0 ? 'yes' : 'no',
162 'is_onboarded' => $this->getOnboardingValue()
163 ]);
164 }
165
166 public function getMenuItems($app)
167 {
168 $config = $app->config;
169 $slug = $config->get('app.slug');
170
171 $baseUrl = fluent_boards_page_url();
172
173 $isDiffUrl = false;
174
175 if (is_admin()) {
176 $adminUrl = admin_url('admin.php?page=fluent-boards#/');
177
178 if ($adminUrl != $baseUrl) {
179 $isDiffUrl = true;
180 $baseUrl = $adminUrl;
181 }
182 }
183
184 $menuItems = [
185 'dashboard' => [
186 'key' => 'dashboard',
187 'label' => __('Dashboard', 'fluent-boards'),
188 'permalink' => $baseUrl,
189 ],
190 'boards' => [
191 'key' => 'boards',
192 'label' => __('Boards', 'fluent-boards'),
193 'permalink' => $baseUrl . 'boards'
194 ]
195 ];
196
197 $menuItems = apply_filters('fluent_boards/core_menu_items', $menuItems);
198
199 $menuItems['reports'] = [
200 'key' => 'reports',
201 'label' => __('Reports', 'fluent-boards'),
202 'permalink' => $baseUrl . 'reports'
203 ];
204
205 $isAdmin = PermissionManager::isAdmin();
206
207 if ($isAdmin) {
208 $menuItems['settings'] = [
209 'key' => 'settings',
210 'label' => __('Settings', 'fluent-boards'),
211 'permalink' => $baseUrl . 'settings/members-role'
212 ];
213 }
214
215 if (!defined('FLUENT_BOARDS_PRO')) {
216 $menuItems['get_pro'] = [
217 'key' => 'get_pro',
218 'label' => __('Get Pro', 'fluent-boards'),
219 'permalink' => 'https://fluentboards.com?utm_source=plugin&utm_medium=menu&utm_campaign=pro&utm_id=wp',
220 'class' => 'pro_link'
221 ];
222 }
223
224 if ($isAdmin) {
225 $menuItems['help'] = [
226 'key' => 'help',
227 'label' => __('Community', 'fluent-boards'),
228 'target' => '_blank',
229 'permalink' => 'https://community.wpmanageninja.com/portal/community/fluent-boards/home'
230 ];
231 }
232
233 if ($isDiffUrl) {
234 $menuItems['front'] = [
235 'key' => 'front',
236 'label' => __('Frontend Portal', 'fluent-boards'),
237 'target' => '_blank',
238 'permalink' => fluent_boards_page_url()
239 ];
240 }
241
242 $menuItems = apply_filters('fluent_boards/menu_items', $menuItems);
243
244 return array_values($menuItems);
245 }
246
247 public function enqueueAssets()
248 {
249 if (!PermissionManager::hasAppAccess()) {
250 return;
251 }
252
253 add_action('wp_print_scripts', function () {
254
255 $isSkip = apply_filters('fluent_boards/skip_no_conflict', false);
256
257 if ($isSkip) {
258 return;
259 }
260
261 global $wp_scripts;
262 if (!$wp_scripts) {
263 return;
264 }
265
266 $approvedSlugs = apply_filters('fluent_boards/asset_listed_slugs', [
267 '\/fluent-crm\/'
268 ]);
269
270 $approvedSlugs[] = '\/fluent-boards\/';
271
272 $approvedSlugs = array_unique($approvedSlugs);
273
274 $approvedSlugs = implode('|', $approvedSlugs);
275
276 $pluginUrl = plugins_url();
277
278 $pluginUrl = str_replace(['http:', 'https:'], '', $pluginUrl);
279
280 foreach ($wp_scripts->queue as $script) {
281 if (empty($wp_scripts->registered[$script]) || empty($wp_scripts->registered[$script]->src)) {
282 continue;
283 }
284
285 $src = $wp_scripts->registered[$script]->src;
286 $isMatched = (strpos($src, $pluginUrl) !== false) && !preg_match('/' . $approvedSlugs . '/', $src);
287 if (!$isMatched) {
288 continue;
289 }
290 wp_dequeue_script($wp_scripts->registered[$script]->handle);
291 }
292 });
293
294 if (function_exists('wp_enqueue_media')) {
295 // Editor default styles.
296 add_filter('user_can_richedit', '__return_true');
297 if (is_admin()) {
298 wp_tinymce_inline_scripts();
299 }
300 wp_enqueue_editor();
301 wp_enqueue_script('thickbox');
302 wp_enqueue_script('editor');
303 }
304 if (function_exists('wp_enqueue_media')) {
305 wp_enqueue_media();
306 }
307
308 $app = App::getInstance();
309
310 $assets = $app['url.assets'];
311
312 $slug = $app->config->get('app.slug');
313
314 $isRtl = is_rtl();
315 $adminAppCss = 'admin/admin.css';
316 if($isRtl) {
317 $adminAppCss = 'admin/admin-rtl.css';
318 }
319 wp_enqueue_style(
320 $slug . '_admin_app',
321 $assets . $adminAppCss,
322 [],
323 FLUENT_BOARDS_PLUGIN_VERSION
324 );
325
326 do_action('fluent-boards_loading_app');
327
328 wp_enqueue_script(
329 $slug . '_admin_app',
330 $assets . 'admin/app.min.js',
331 ['jquery'],
332 FLUENT_BOARDS_PLUGIN_VERSION,
333 true
334 );
335
336 wp_enqueue_script(
337 $slug . '_global_admin',
338 $assets . 'admin/global_admin.js',
339 [],
340 FLUENT_BOARDS_PLUGIN_VERSION,
341 true
342 );
343 /*
344 * This script only for resolve the conflict of lodash and underscore js
345 * Resolved the issue of media uploader specially for image upload
346 */
347 wp_add_inline_script($slug . '_global_admin', $this->getInlineScript(), 'after');
348
349 wp_localize_script($slug . '_admin_app', 'fluentAddonVars', $this->getAddonVars($app));
350
351 do_action('fluent_boards/after_enqueue_assets', $app);
352 }
353
354 public function getAddonVars($app)
355 {
356 $currentUser = get_user_by('ID', get_current_user_id());
357 $assets = $app['url.assets'];
358 $roleAndPermissions = $this->getRoleAndPermissions($currentUser->ID);
359 $onboardingValue = $this->getOnboardingValue();
360
361 return apply_filters('fluent_boards/app_vars', [
362 'slug' => $slug = $app->config->get('app.slug'),
363 'nonce' => wp_create_nonce($slug),
364 'rest' => $this->getRestInfo($app),
365 'fluent_boards_file_upload_nonce' => wp_create_nonce('fluent_boards_file_upload_nonce'),
366 'ajaxurl' => admin_url('admin-ajax.php'),
367 'file_upload_limit' => $this->fileUploadLimit(),
368 'brand_logo' => $this->getMenuIcon(),
369 'asset_url' => $assets,
370 'admin_url' => admin_url('admin.php'),
371 'fluent_crm_exists' => !defined('FLUENTCRM') ? false : true,
372 'fluent_roadmap_exists' => !defined('FLUENT_ROADMAP') ? false : true,
373 'has_pro' => !!defined('FLUENT_BOARDS_PRO_VERSION'),
374 'me' => [
375 'id' => $currentUser->ID,
376 'full_name' => trim($currentUser->first_name . ' ' . $currentUser->last_name),
377 'display_name' => $currentUser->display_name,
378 'email' => $currentUser->user_email,
379 'photo' => fluent_boards_user_avatar($currentUser->user_email, $currentUser->display_name),
380 'fluent_boards_role' => $roleAndPermissions['role'],
381 'fluent_boards_capabilities' => $roleAndPermissions['permissions'],
382 'is_wp_admin' => user_can($currentUser->ID, 'manage_options') ? 'yes' : 'no'
383 ],
384 'base_url' => fluent_boards_page_url(),
385 'site_url' => site_url('/'),
386 // 'server_time' => (new DateTime('now'))->format('Y-m-d H:i:s P'), // Server's default timezone
387 'server_time' => (new DateTime('now', wp_timezone()))->format('Y-m-d H:i:s P'), // wordpress site time
388 'server_time_zone' => (new DateTime('now', wp_timezone()))->format( 'P'),
389 'utc_offset' => current_time('timestamp') - strtotime(gmdate('Y-m-d H:i:s')),
390 'trans' => TransStrings::getStrings(),
391 'is_new' => Board::count() == 0 ? 'yes' : 'no',
392 'is_onboarded' => $onboardingValue,
393 'render_in' => is_admin() ? 'admin' : 'front',
394 'dashboard_notices' => apply_filters('fluent_boards/dashboard_notices', []),
395 'is_beta' => defined('FLUENT_BOARDS_PRO_VERSION') && !defined('FLUENT_BOARDS_PRO_LIVE'),
396 'advanced_modules' => fluent_boards_get_pref_settings(),
397 'crm_base_url' => defined('FLUENTCRM') ? fluentcrm_menu_url_base() : '',
398 'start_of_week' => intval(get_option('start_of_week', 0)),
399 'time_format' => get_option('time_format', 'g:i'),
400 'priorities' => apply_filters('fluent_boards/task_priorities', $this->getDefaultPriorities()),
401 'wpContentCss' => add_query_arg(
402 'ver', get_bloginfo('version'),
403 site_url('/wp-includes/js/tinymce/skins/wordpress/wp-content.css')
404 ),
405 'dashiconsCss' => add_query_arg(
406 'ver', get_bloginfo('version'),
407 site_url('/wp-includes/css/dashicons.css')
408 ),
409 'is_rtl' => is_rtl(),
410 'task_tabs' => apply_filters('fluent_boards/task_tabs', $this->getDefaultTaskTabs()),
411 'board_menu_items' => BoardMenuHandler::getMenuItems(),
412 'reminder_types' => defined('FLUENT_BOARDS_PRO') ? Helper::taskReminderTypes() : [],
413 ]);
414 }
415
416 private function getOnboardingValue()
417 {
418 $onboarding = Meta::where('key', Constant::FBS_ONBOARDING)->first();
419 if ($onboarding) {
420 return $onboarding->value;
421 }
422 // if (Board::first()) {
423 // return 'yes';
424 // }
425 //
426 // return 'no';
427 }
428
429 private function getDefaultTaskTabs()
430 {
431 return [
432 'all' => [
433 'key' => 'all',
434 'label' => __('All', 'fluent-boards'),
435 'component' => 'task-all-comments-and-activities'
436 ],
437 'comment' => [
438 'key' => 'comment',
439 'label' => __('Comments', 'fluent-boards'),
440 'component' => 'task-comments'
441 ],
442 'activity' => [
443 'key' => 'activity',
444 'label' => __('Activities', 'fluent-boards'),
445 'component' => 'task-activities'
446 ]
447 ];
448 }
449 public function getDefaultPriorities()
450 {
451 return [
452 'low' => __('Low', 'fluent-boards'),
453 'medium' => __('Medium', 'fluent-boards'),
454 'high' => __('High', 'fluent-boards')
455 ];
456 }
457
458 /*
459 * TODO: This method should be moved to PermissionManager and Helper . Task for Masiur.
460 */
461 protected function getRoleAndPermissions($userId): array
462 {
463 $role = 'fluent_boards_admin';
464 $boardsWithPermissions = Relation::query()->where('foreign_id', $userId)
465 ->where('object_type', Constant::OBJECT_TYPE_BOARD_USER)
466 ->get();
467 $boardUserCollection = Collection::make($boardsWithPermissions);
468
469 if (PermissionManager::isFluentBoardsAdmin($userId)) {
470 $role = 'fluent_boards_admin';
471 } elseif (user_can($userId, 'manage_options')) {
472 $role = 'wordpress_admin';
473 } else {
474 $role = 'member';
475 }
476
477 $permissions = [];
478 foreach ($boardUserCollection as $boardWithPermission) {
479 $permissions[] = [
480 'board_id' => $boardWithPermission->object_id,
481 'role' => $this->boardUserRole($boardWithPermission),
482 'preferences' => $boardWithPermission->preferences,
483 'permissions' => [],
484 ];
485 }
486
487 return [
488 'role' => $role,
489 'permissions' => $permissions,
490 ];
491 }
492
493 protected function boardUserRole($boardWithPermission)
494 {
495 return $boardWithPermission['settings']['is_admin'] ? 'board_admin' : (Arr::has($boardWithPermission, 'settings.is_viewer_only') && $boardWithPermission['settings']['is_viewer_only'] ? 'board_viewer' : 'board_member');
496 }
497
498 protected function getRestInfo($app)
499 {
500 $ns = $app->config->get('app.rest_namespace');
501 $ver = $app->config->get('app.rest_version');
502
503 return [
504 'base_url' => esc_url_raw(rest_url()),
505 'url' => rest_url($ns . '/' . $ver),
506 'nonce' => wp_create_nonce('wp_rest'),
507 'namespace' => $ns,
508 'version' => $ver,
509 ];
510 }
511
512 protected function getMenuIcon()
513 {
514 /*
515 * Left Sidebar Menu Icon
516 */
517 return 'data:image/svg+xml;base64,' . base64_encode('<svg width="256" height="256" viewBox="0 0 256 256" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M0 25.6C0 11.4615 11.4615 0 25.6 0H230.4C244.538 0 256 11.4615 256 25.6V230.4C256 244.538 244.538 256 230.4 256H25.6C11.4615 256 0 244.538 0 230.4V25.6ZM140.8 89.6C140.8 75.4615 152.262 64 166.4 64H186.88C189.708 64 192 66.2923 192 69.12V166.4C192 180.538 180.538 192 166.4 192H145.92C143.092 192 140.8 189.708 140.8 186.88V89.6ZM89.6 64C75.4615 64 64 75.4615 64 89.5999V148.48C64 151.308 66.2923 153.6 69.12 153.6H89.6C103.739 153.6 115.2 142.138 115.2 128V69.12C115.2 66.2923 112.908 64 110.08 64H89.6Z" fill="white"/></svg>');
518 }
519
520 public function changeFooter()
521 {
522 add_filter('admin_footer_text', function ($content) {
523 $url = '#';
524 return '';
525
526 // translators: %s is the URL for FluentBoards link
527 return sprintf(wp_kses(__('Thank you for using <a href="%s">FluentBoards</a>', 'fluent-boards'), ['a' => ['href' => []]]), esc_url($url)) . '<span title="based on your WP timezone settings" style="margin-left: 10px;" data-timestamp="' . current_time('timestamp') . '" id="fc_server_timestamp"></span>';
528 });
529
530 add_filter('update_footer', function ($text) {
531 return FLUENT_BOARDS_PLUGIN_VERSION;
532 });
533 }
534
535 /**
536 * Retrieves the maximum upload limit based on PHP and WordPress configurations.
537 *
538 * This method calculates and returns the minimum value among the following:
539 * 1. The PHP 'upload_max_filesize' configuration.
540 * 2. The PHP 'post_max_size' configuration.
541 * 3. The WordPress maximum upload size limit using the 'wp_max_upload_size' function.
542 *
543 * @return int The minimum of the mentioned upload size limits in bytes.
544 */
545 public function fileUploadLimit()
546 {
547 // Calculate the minimum of 'upload_max_filesize', 'post_max_size', and WordPress maximum upload size.
548 return min(
549 wp_convert_hr_to_bytes(ini_get('upload_max_filesize')),
550 wp_convert_hr_to_bytes(ini_get('post_max_size')),
551 wp_max_upload_size()
552 );
553 }
554
555 public function getInlineScript()
556 {
557 return "
558 function isLodash () {
559
560 let isLodash = false;
561
562 // If _ is defined and the function _.forEach exists then we know underscore OR lodash are in place
563 if ( 'undefined' != typeof( _ ) && 'function' == typeof( _.forEach ) ) {
564
565 // A small sample of some of the functions that exist in lodash but not underscore
566 const funcs = [ 'get', 'set', 'at', 'cloneDeep' ];
567
568 // Simplest if assume exists to start
569 isLodash = true;
570
571 funcs.forEach( function ( func ) {
572 // If just one of the functions do not exist, then not lodash
573 isLodash = ( 'function' != typeof( _[ func ] ) ) ? false : isLodash;
574 } );
575 }
576
577 if ( isLodash ) {
578 // We know that lodash is loaded in the _ variable
579 return true;
580 } else {
581 // We know that lodash is NOT loaded
582 return false;
583 }
584 };
585
586 if ( isLodash() ) {
587 _.noConflict();
588 }
589 ";
590 }
591 public function singleBoardRender()
592 {
593 $config = App::getInstance('config');
594
595 $slug = $config->get('app.slug');
596
597
598
599 App::make('view')->render('admin.single_board_shortcode', [
600 'slug' => $slug,
601 ]);
602 }
603
604 }
605