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.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.45, at app/Hooks/Handlers/AdminMenuHandler.php

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