PluginProbe
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration / 1.32
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration v1.32
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.32, at app/Hooks/Handlers/AdminMenuHandler.php

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