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

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