Passed
Push — master ( 5154a4...7dea86 )
by Nils
04:26
created

getNodeInfos()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 48
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 5
eloc 22
nc 5
nop 7
dl 0
loc 48
rs 9.2568
c 2
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * Teampass - a collaborative passwords manager.
7
 * ---
8
 * This library is distributed in the hope that it will be useful,
9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11
 *
12
 * @project   Teampass
13
 * @file      tree.php
14
 *
15
 * @author    Nils Laumaillé ([email protected])
16
 * @copyright 2009-2022 Teampass.net
17
 * @license   https://spdx.org/licenses/GPL-3.0-only.html#licenseText GPL-3.0
18
 *
19
 * @see       https://www.teampass.net
20
 */
21
22
23
require_once 'SecureHandler.php';
24
session_name('teampass_session');
25
session_start();
26
if (
27
    isset($_SESSION['CPM']) === false
28
    || $_SESSION['CPM'] !== 1
29
    || isset($_SESSION['key']) === false
30
    || empty($_SESSION['key']) === true
31
) {
32
    die('Hacking attempt...');
33
}
34
35
// Load config
36
if (file_exists('../includes/config/tp.config.php')) {
37
    include_once '../includes/config/tp.config.php';
38
} elseif (file_exists('./includes/config/tp.config.php')) {
39
    include_once './includes/config/tp.config.php';
40
} else {
41
    throw new Exception("Error file '/includes/config/tp.config.php' not exists", 1);
42
}
43
44
// includes
45
require_once $SETTINGS['cpassman_dir'] . '/includes/config/include.php';
46
require_once $SETTINGS['cpassman_dir'] . '/sources/SplClassLoader.php';
47
require_once $SETTINGS['cpassman_dir'] . '/sources/main.functions.php';
48
require_once $SETTINGS['cpassman_dir'] . '/includes/language/' . $_SESSION['user_language'] . '.php';
49
require_once $SETTINGS['cpassman_dir'] . '/includes/config/settings.php';
50
51
// header
52
header('Content-type: text/html; charset=utf-8');
53
header('Cache-Control: no-cache, must-revalidate');
54
55
// Define Timezone
56
if (isset($SETTINGS['timezone'])) {
57
    date_default_timezone_set($SETTINGS['timezone']);
58
} else {
59
    date_default_timezone_set('UTC');
60
}
61
62
// Connect to mysql server
63
require_once $SETTINGS['cpassman_dir'] . '/includes/libraries/Database/Meekrodb/db.class.php';
64
if (defined('DB_PASSWD_CLEAR') === false) {
65
    define('DB_PASSWD_CLEAR', defuseReturnDecrypted(DB_PASSWD, $SETTINGS));
66
}
67
DB::$host = DB_HOST;
68
DB::$user = DB_USER;
69
DB::$password = DB_PASSWD_CLEAR;
70
DB::$dbName = DB_NAME;
71
DB::$port = DB_PORT;
72
DB::$encoding = DB_ENCODING;
73
74
// Superglobal load
75
require_once $SETTINGS['cpassman_dir'] . '/includes/libraries/protect/SuperGlobal/SuperGlobal.php';
76
$superGlobal = new protect\SuperGlobal\SuperGlobal();
77
$get = [];
78
$get['user_tree_structure'] = $superGlobal->get('user_tree_structure', 'GET');
79
$get['user_tree_last_refresh_timestamp'] = $superGlobal->get('user_tree_last_refresh_timestamp', 'GET');
80
$get['force_refresh'] = $superGlobal->get('force_refresh', 'GET');
81
$get['id'] = $superGlobal->get('id', 'GET');
82
$session = [];
83
$session['forbiden_pfs'] = $superGlobal->get('forbiden_pfs', 'SESSION');
84
$session['groupes_visibles'] = $superGlobal->get('groupes_visibles', 'SESSION');
85
$session['list_restricted_folders_for_items'] = $superGlobal->get('list_restricted_folders_for_items', 'SESSION');
86
$session['user_id'] = $superGlobal->get('user_id', 'SESSION');
87
$session['login'] = $superGlobal->get('login', 'SESSION');
88
$session['user_read_only'] = $superGlobal->get('user_read_only', 'SESSION');
89
//$session['personal_folder'] = explode(';', $superGlobal->get('personal_folder', 'SESSION'));
90
$session['list_folders_limited'] = $superGlobal->get('list_folders_limited', 'SESSION');
91
$session['read_only_folders'] = $superGlobal->get('read_only_folders', 'SESSION');
92
$session['personal_visible_groups'] = $superGlobal->get('personal_visible_groups', 'SESSION');
93
$lastFolderChange = DB::query(
94
    'SELECT * FROM ' . prefixTable('misc') . '
95
    WHERE type = %s AND intitule = %s',
96
    'timestamp',
97
    'last_folder_change'
98
);
99
if (
100
    empty($get['user_tree_structure']) === true
101
    || ($get['user_tree_last_refresh_timestamp'] !== null && strtotime($lastFolderChange) > strtotime($get['user_tree_last_refresh_timestamp']))
102
    || (isset($get['force_refresh']) === true && (int) $get['force_refresh'] === 1)
103
) {
104
    // Build tree
105
    $tree = new SplClassLoader('Tree\NestedTree', $SETTINGS['cpassman_dir'] . '/includes/libraries');
106
    $tree->register();
107
    $tree = new Tree\NestedTree\NestedTree(prefixTable('nested_tree'), 'id', 'parent_id', 'title');
108
109
    if (
110
        isset($session['list_folders_limited']) === true
111
        && is_array($session['list_folders_limited']) === true
112
        && count($session['list_folders_limited']) > 0
113
    ) {
114
        $listFoldersLimitedKeys = array_keys($session['list_folders_limited']);
115
    } else {
116
        $listFoldersLimitedKeys = array();
117
    }
118
    
119
    // list of items accessible but not in an allowed folder
120
    if (
121
        isset($session['list_restricted_folders_for_items']) === true
122
        && count($session['list_restricted_folders_for_items']) > 0
123
    ) {
124
        $listRestrictedFoldersForItemsKeys = @array_keys($session['list_restricted_folders_for_items']);
125
    } else {
126
        $listRestrictedFoldersForItemsKeys = array();
127
    }
128
    
129
    //$_SESSION['user_treeloadstrategy'] = 'sequential';
130
    $ret_json = array();
131
    $last_visible_parent = -1;
132
    $last_visible_parent_level = 1;
133
    $nodeId = isset($get['id']) === true && is_int($get['id']) === true ? $get['id'] : 0;
134
135
    // build the tree to be displayed
136
    if (showFolderToUser(
137
        $nodeId,
138
        $session['forbiden_pfs'],
139
        $session['groupes_visibles'],
140
        $listFoldersLimitedKeys,
141
        $listRestrictedFoldersForItemsKeys
142
    ) === true)
143
    {
144
        if (isset($_SESSION['user_treeloadstrategy']) === true
145
            && $_SESSION['user_treeloadstrategy'] === 'sequential'
146
        ) {
147
            // SEQUENTIAL MODE
148
            // Is this folder visible by user
149
            $ret_json = buildNodeTree(
150
                $nodeId,
151
                $listFoldersLimitedKeys,
152
                $listRestrictedFoldersForItemsKeys,
153
                /** @scrutinizer ignore-type */ $tree,
154
                $SETTINGS,
155
                $session['forbiden_pfs'],
156
                $session['groupes_visibles'],
157
                $session['list_restricted_folders_for_items'],
158
                $session['user_id'],
159
                $session['login'],
160
                $superGlobal->get('no_access_folders', 'SESSION'),
161
                $superGlobal->get('personal_folders', 'SESSION'),
162
                $session['list_folders_limited'],
163
                $session['read_only_folders'],
164
                $superGlobal->get('personal_folders', 'SESSION'),
165
                $session['personal_visible_groups'],
166
                $session['user_read_only']
0 ignored issues
show
Unused Code introduced by
The call to buildNodeTree() has too many arguments starting with $session['user_read_only']. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

166
            $ret_json = /** @scrutinizer ignore-call */ buildNodeTree(

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
167
            );
168
        } else {
169
            // FULL MODE
170
            $completTree = $tree->getTreeWithChildren();
171
            foreach ($completTree[0]->children as $child) {
172
                recursiveTree(
173
                    $child,
174
                    $completTree,
175
                    /** @scrutinizer ignore-type */ $tree,
176
                    $listFoldersLimitedKeys,
177
                    $listRestrictedFoldersForItemsKeys,
178
                    $last_visible_parent,
179
                    $last_visible_parent_level,
180
                    $SETTINGS,
181
                    $session['forbiden_pfs'],
182
                    $session['groupes_visibles'],
183
                    $session['list_restricted_folders_for_items'],
184
                    $session['user_id'],
185
                    $session['login'],
186
                    $session['user_read_only'],
187
                    $superGlobal->get('personal_folders', 'SESSION'),
188
                    $session['list_folders_limited'],
189
                    $session['read_only_folders'],
190
                    $session['personal_visible_groups'],
191
                    $superGlobal->get('can_create_root_folder', 'SESSION'),
192
                    $ret_json
193
                );
194
            }
195
        }
196
    }
197
198
    // Save in SESSION
199
    $superGlobal->put('user_tree_structure', $ret_json, 'SESSION');
200
    $superGlobal->put('user_tree_last_refresh_timestamp', time(), 'SESSION');
201
202
    // Send back
203
    echo json_encode($ret_json);
204
} else {
205
    echo $get['user_tree_structure'];
206
}
207
208
/**
209
 * Check if user can see this folder based upon rights
210
 *
211
 * @param integer $nodeId
212
 * @param array $session_forbiden_pfs
213
 * @param array $session_groupes_visibles
214
 * @param array $listFoldersLimitedKeys
215
 * @param array $listRestrictedFoldersForItemsKeys
216
 * @return boolean
217
 */
218
function showFolderToUser(
219
    int $nodeId,
220
    array $session_forbiden_pfs,
221
    array $session_groupes_visibles,
222
    array $listFoldersLimitedKeys,
223
    array $listRestrictedFoldersForItemsKeys,
224
): bool
225
{
226
    if (
227
        in_array($nodeId, $session_forbiden_pfs) === false
228
        || in_array($nodeId, $session_groupes_visibles) === true
229
        || in_array($nodeId, $listFoldersLimitedKeys) === true
230
        || in_array($nodeId, $listRestrictedFoldersForItemsKeys) === true
231
    ) {
232
        return true;
233
    }
234
    return false;
235
}
236
237
/**
238
 * Get through asked folders
239
 *
240
 * @param int $nodeId
241
 * @param array $listFoldersLimitedKeys
242
 * @param array $listRestrictedFoldersForItemsKeys
243
 * @param array $tree
244
 * @param array $SETTINGS
245
 * @param array $session_forbiden_pfs
246
 * @param array $session_groupes_visibles
247
 * @param array $session_list_restricted_folders_for_items
248
 * @param int $session_user_id
249
 * @param string $session_login
250
 * @param array $session_no_access_folders
251
 * @param array $session_list_folders_limited
252
 * @param array $session_read_only_folders
253
 * @param array $session_personal_folders
254
 * @param array $session_personal_visible_groups
255
 * @param int $session_user_read_only
256
 * @return array
257
 */
258
function buildNodeTree(
259
    $nodeId,
260
    $listFoldersLimitedKeys,
261
    $listRestrictedFoldersForItemsKeys,
262
    $tree,
263
    $SETTINGS,
264
    $session_forbiden_pfs,
265
    $session_groupes_visibles,
266
    $session_list_restricted_folders_for_items,
267
    $session_user_id,
268
    $session_login,
269
    $session_no_access_folders,
270
    $session_list_folders_limited,
271
    $session_read_only_folders,
272
    $session_personal_folders,
273
    $session_personal_visible_groups,
274
    $session_user_read_only
275
) {
276
    // Prepare superGlobal variables
277
    $ret_json = array();
278
    $nbChildrenItems = 0;
279
280
    // Check if any allowed folder is part of the descendants of this node
281
    $nodeDescendants = $tree->getDescendants($nodeId, false, true, false);
282
    foreach ($nodeDescendants as $node) {
283
        if (showFolderToUser(
284
                $node->id,
285
                $session_forbiden_pfs,
286
                $session_groupes_visibles,
287
                $listFoldersLimitedKeys,
288
                $listRestrictedFoldersForItemsKeys
289
            ) === true
290
            && (in_array(
291
                $node->id,
292
                array_merge($session_groupes_visibles, $session_list_restricted_folders_for_items)
293
            ) === true
294
                || (is_array($listFoldersLimitedKeys) === true && in_array($node->id, $listFoldersLimitedKeys) === true)
295
                || (is_array($listRestrictedFoldersForItemsKeys) === true && in_array($node->id, $listRestrictedFoldersForItemsKeys) === true)
296
                || in_array($node->id, $session_no_access_folders) === true)
297
        ) {
298
            $nodeElements= buildNodeTreeElements(
299
                $node,
300
                $session_user_id,
301
                $session_login,
302
                $session_user_read_only,
303
                $session_personal_folders,
304
                $session_groupes_visibles,
305
                $session_read_only_folders,
306
                $session_personal_visible_groups,
307
                $nbChildrenItems,
308
                $nodeDescendants,
309
                $listFoldersLimitedKeys,
310
                $session_list_folders_limited,
311
                $listRestrictedFoldersForItemsKeys,
312
                $session_list_restricted_folders_for_items,
313
                $SETTINGS,
314
                $tree->numDescendants($node->id)
315
            );
316
317
            // json    
318
            array_push(
319
                $ret_json,
320
                array(
321
                    'id' => 'li_' . $node->id,
322
                    'parent' => $nodeElements['parent'],
323
                    'text' => '<i class="fas fa-folder mr-2"></i>'.($nodeElements['show_but_block'] === true ? '<i class="fas fa-times fa-xs text-danger mr-1"></i>' : '') . $nodeElements['text'],
324
                    'children' => ($nodeElements['childrenNb'] === 0 ? false : true),
325
                    'fa_icon' => 'folder',
326
                    'li_attr' => array(
327
                        'class' => ($nodeElements['show_but_block'] === true ? '' : 'jstreeopen'),
328
                        'title' => 'ID [' . $node->id . '] ' . ($nodeElements['show_but_block'] === true ? langHdl('no_access') : $nodeElements['title']),
329
                    ),
330
                    'a_attr' => $nodeElements['show_but_block'] === true ? (array(
331
                        'id' => 'fld_' . $node->id,
332
                        'class' => $nodeElements['folderClass'],
333
                        'onclick' => 'ListerItems(' . $node->id . ', ' . $nodeElements['restricted'] . ', 0, 1)',
334
                        'data-title' => $node->title,
335
                    )) : '',
336
                    'is_pf' => in_array($node->id, $session_personal_folders) === true ? 1 : 0,
337
                )
338
            );
339
        }
340
    }
341
342
    return $ret_json;
343
}
344
345
/**
346
 * Get some infos for this node
347
 *
348
 * @param integer   $nodeId
349
 * @param integer   $nodeLevel
350
 * @param string    $nodeTitle
351
 * @param integer   $userId
352
 * @param string    $userLogin
353
 * @param bool      $userIsRO
354
 * @param array     $userPF
355
 * @return array
356
 */
357
function getNodeInfos(
358
    int $nodeId,
359
    int $nodeLevel,
360
    string $nodeTitle,
361
    int $userId,
362
    string $userLogin,
363
    bool $userIsRO,
364
    array $userPF
365
) : array
366
{
367
    $ret = [];
368
    // get count of Items in this folder
369
    DB::query(
370
        'SELECT *
371
        FROM ' . prefixTable('items') . '
372
        WHERE inactif=%i AND id_tree = %i',
373
        0,
374
        $nodeId
375
    );
376
    $ret['itemsNb'] = DB::count();
377
378
    // get info about current folder
379
    DB::query(
380
        'SELECT *
381
        FROM ' . prefixTable('nested_tree') . '
382
        WHERE parent_id = %i',
383
        $nodeId
384
    );
385
    $ret['childrenNb'] = DB::count();
386
387
    // Manage node title
388
    if ($userIsRO === true && in_array($nodeId, $userPF) === false) {
389
        // special case for READ-ONLY folder
390
        $ret['title'] = langHdl('read_only_account');
391
    } else {
392
        // If personal Folder, convert id into user name
393
        $ret['title'] = (string) $nodeTitle === (string) $userId && (int) $nodeLevel === 1 ?
394
        $userLogin :
395
        htmlspecialchars_decode($nodeTitle, ENT_QUOTES);
396
    }
397
398
    $ret['text'] = str_replace(
399
        '&',
400
        '&amp;',
401
        $ret['nodeTitle']
402
    );
403
404
    return $ret;
405
}
406
407
function buildNodeTreeElements(
408
    $node,
409
    $session_user_id,
410
    $session_login,
411
    $session_user_read_only,
412
    $session_personal_folders,
413
    $session_groupes_visibles,
414
    $session_read_only_folders,
415
    $session_personal_visible_groups,
416
    $nbChildrenItems,
417
    $nodeDescendants,
418
    $listFoldersLimitedKeys,
419
    $session_list_folders_limited,
420
    $listRestrictedFoldersForItemsKeys,
421
    $session_list_restricted_folders_for_items,
422
    $SETTINGS,
423
    $numDescendants
424
)
425
{
426
    // Get info for this node
427
    $nodeInfos = getNodeInfos(
428
        $node->id,
429
        $node->nlevel,
430
        $node->title,
431
        $session_user_id,
432
        $session_login,
433
        $session_user_read_only,
434
        $session_personal_folders
435
    );
436
    $itemsNb = $nodeInfos['itemsNb'];
437
    $childrenNb = $nodeInfos['childrenNb'];
438
    $title = $nodeInfos['title'];
439
    $text = $nodeInfos['text'];
440
441
    // prepare json return for current node
442
    $parent = $node->parent_id === 0 ? '#' : 'li_' . $node->parent_id;
443
444
    if (in_array($node->id, $session_groupes_visibles) === true) {
445
        if (in_array($node->id, $session_read_only_folders) === true) {
446
            return array(
447
                'text' => '<i class="far fa-eye fa-xs mr-1 ml-1"></i>' . $text
448
                    .' <span class=\'badge badge-danger ml-2 items_count\' id=\'itcount_' . $node->id . '\'>' . $itemsNb . '</span>'
449
                    .(isKeyExistingAndEqual('tree_counters', 1, $SETTINGS) === true ?
450
                        '/'.$nbChildrenItems .'/'.(count($nodeDescendants) - 1)
451
                        : '')
452
                    .'</span>',
453
                'title' => langHdl('read_only_account'),
454
                'restricted' => 1,
455
                'folderClass' => 'folder_not_droppable',
456
                'show_but_block' => false,
457
                'parent' => $parent,
458
                'childrenNb' => $childrenNb,
459
                'itemsNb' => $itemsNb,
460
            );
461
        }
462
        
463
        return array(
464
            'text' => ($session_user_read_only === true && in_array($node->id, $session_personal_visible_groups) === false) ?
465
                ('<i class="far fa-eye fa-xs mr-1 ml-1"></i>' . $text
466
                .' <span class=\'badge badge-danger ml-2 items_count\' id=\'itcount_' . $node->id . '\'>' . $itemsNb . '</span>'
467
                .(isKeyExistingAndEqual('tree_counters', 1, $SETTINGS) === true ?
468
                    '/'.$nbChildrenItems .'/'.(count($nodeDescendants) - 1)  :
469
                    '')
470
                .'</span>') :
471
                (' <span class=\'badge badge-danger ml-2 items_count\' id=\'itcount_' . $node->id . '\'>' . $itemsNb . '</span>'
472
                .(isKeyExistingAndEqual('tree_counters', 1, $SETTINGS) === true ?
473
                    '/'.$nbChildrenItems .'/'.(count($nodeDescendants) - 1)  :
474
                    '')
475
                .'</span>'),
476
            'title' => langHdl('read_only_account'),
477
            'restricted' => 1,
478
            'folderClass' => 'folder_not_droppable',
479
            'show_but_block' => false,
480
            'parent' => $parent,
481
            'childrenNb' => $childrenNb,
482
            'itemsNb' => $itemsNb,
483
        );
484
    }
485
    
486
    if (in_array($node->id, $listFoldersLimitedKeys) === true) {
487
        return array(
488
            'text' => $text . ($session_user_read_only === true ?
489
                '<i class="far fa-eye fa-xs mr-1 ml-1"></i>' :
490
                '<span class="badge badge-danger ml-2 items_count" id="itcount_' . $node->id . '">' . count($session_list_folders_limited[$node->id]) . '</span>'
491
            ),
492
            'title' => $title,
493
            'restricted' => 1,
494
            'folderClass' => 'folder',
495
            'show_but_block' => false,
496
            'parent' => $parent,
497
            'childrenNb' => $childrenNb,
498
            'itemsNb' => $itemsNb,
499
        );
500
    }
501
    
502
    if (in_array($node->id, $listRestrictedFoldersForItemsKeys) === true) {        
503
        return array(
504
            'text' => $text . ($session_user_read_only === true ? 
505
                '<i class="far fa-eye fa-xs mr-1 ml-1"></i>' :
506
                '<span class="badge badge-danger ml-2 items_count" id="itcount_' . $node->id . '">' . count($session_list_restricted_folders_for_items[$node->id]) . '</span>'
507
            ),
508
            'title' => $title,
509
            'restricted' => 1,
510
            'folderClass' => 'folder',
511
            'show_but_block' => false,
512
            'parent' => $parent,
513
            'childrenNb' => $childrenNb,
514
            'itemsNb' => $itemsNb,
515
        );
516
    }
517
518
    // default case
519
    if (isKeyExistingAndEqual('show_only_accessible_folders', 1, $SETTINGS) === true
520
        && (int) $numDescendants === 0)
521
    {
522
        return array();
523
    }
524
525
    return array(
526
        'text' => $text,
527
        'title' => $title,
528
        'restricted' => 1,
529
        'folderClass' => 'folder_not_droppable',
530
        'show_but_block' => true,   // folder is visible but not accessible by user
531
        'parent' => $parent,
532
        'childrenNb' => $childrenNb,
533
        'itemsNb' => $itemsNb,
534
    );
535
}
536
537
/**
538
 * Get through complete tree
539
 *
540
 * @param int     $nodeId                            Id
541
 * @param array   $completTree                       Tree info
542
 * @param array   $tree                              The tree
543
 * @param array   $listFoldersLimitedKeys            Limited
544
 * @param array   $listRestrictedFoldersForItemsKeys Restricted
545
 * @param int     $last_visible_parent               Visible parent
546
 * @param int     $last_visible_parent_level         Parent level
547
 * @param array   $SETTINGS                          Teampass settings
548
 * @param string  $session_forbiden_pfs,
549
 * @param string  $session_groupes_visibles,
550
 * @param string  $session_list_restricted_folders_for_items,
551
 * @param int     $session_user_id,
552
 * @param string  $session_login,
553
 * @param string  $session_user_read_only,
554
 * @param array   $session_personal_folder,
555
 * @param string  $session_list_folders_limited,
556
 * @param string  $session_read_only_folders,
557
 * @param string  $session_personal_visible_groups
558
 * @param int     $can_create_root_folder
559
 * @param array   $ret_json                          Array
560
 *
561
 * @return array
562
 */
563
function recursiveTree(
564
    $nodeId,
565
    $completTree,
566
    $tree,
567
    $listFoldersLimitedKeys,
568
    $listRestrictedFoldersForItemsKeys,
569
    $last_visible_parent,
570
    $last_visible_parent_level,
571
    $SETTINGS,
572
    $session_forbiden_pfs,
573
    $session_groupes_visibles,
574
    $session_list_restricted_folders_for_items,
575
    $session_user_id,
576
    $session_login,
577
    $session_user_read_only,
578
    $session_personal_folder,
579
    $session_list_folders_limited,
580
    $session_read_only_folders,
581
    $session_personal_visible_groups,
582
    $can_create_root_folder,
583
    &$ret_json = array()
584
) {
585
    $text = '';
586
    $title = '';
587
    $show_but_block = false;
588
589
    // Load config
590
    if (file_exists('../includes/config/tp.config.php')) {
591
        include '../includes/config/tp.config.php';
592
    } elseif (file_exists('./includes/config/tp.config.php')) {
593
        include './includes/config/tp.config.php';
594
    } else {
595
        throw new Exception("Error file '/includes/config/tp.config.php' not exists", 1);
596
    }
597
    
598
    // Be sure that user can only see folders he/she is allowed to
599
    if (
600
        in_array($completTree[$nodeId]->id, $session_forbiden_pfs) === false
601
        || in_array($completTree[$nodeId]->id, $session_groupes_visibles) === true
602
    ) {
603
        $displayThisNode = false;
604
        $nbChildrenItems = 0;
605
        $nodeDirectDescendants = $tree->getDescendants($completTree[$nodeId]->id, false, false, true);
606
607
        // Check if any allowed folder is part of the descendants of this node
608
        $nodeDescendants = $tree->getDescendants($completTree[$nodeId]->id, true, false, true);
609
        foreach ($nodeDescendants as $node) {
610
            // manage tree counters
611
            if (
612
                isKeyExistingAndEqual('tree_counters', 1, $SETTINGS) === true
613
                && in_array(
614
                    $node,
615
                    array_merge($session_groupes_visibles, $session_list_restricted_folders_for_items)
616
                ) === true
617
            ) {
618
                DB::query(
619
                    'SELECT * FROM ' . prefixTable('items') . '
620
                    WHERE inactif=%i AND id_tree = %i',
621
                    0,
622
                    $node
623
                );
624
                $nbChildrenItems += DB::count();
625
            }
626
627
            if (
628
                in_array($node, $session_groupes_visibles) === true
629
            ) {
630
                // Final check - is PF allowed?
631
                $nodeDetails = $tree->getNode($node);
632
                if (
633
                    (int) $nodeDetails->personal_folder === 1
634
                    && (int) $SETTINGS['enable_pf_feature'] === 1
635
                    && in_array($node, $session_personal_folder) === false
636
                ) {
637
                    $displayThisNode = false;
638
                } else {
639
                    $displayThisNode = true;
640
                    // not adding a break in order to permit a correct count of items
641
                }
642
                $text = '';
643
            }
644
        }
645
        
646
        if ($displayThisNode === true) {
647
            handleNode(
648
                $nodeId,
649
                $completTree,
650
                $tree,
651
                $listFoldersLimitedKeys,
652
                $listRestrictedFoldersForItemsKeys,
653
                $last_visible_parent,
654
                $last_visible_parent_level,
655
                $SETTINGS,
656
                $session_forbiden_pfs,
657
                $session_groupes_visibles,
658
                $session_list_restricted_folders_for_items,
659
                $session_user_id,
660
                $session_login,
661
                $session_user_read_only,
662
                $session_personal_folder,
663
                $session_list_folders_limited,
664
                $session_read_only_folders,
665
                $session_personal_visible_groups,
666
                $text,
667
                $nbChildrenItems,
668
                $nodeDescendants,
669
                $nodeDirectDescendants,
670
                $can_create_root_folder,
671
                $ret_json
672
            );
673
        }
674
    }
675
    return $ret_json;
676
}
677
678
679
function handleNode(
680
    $nodeId,
681
    $completTree,
682
    $tree,
683
    $listFoldersLimitedKeys,
684
    $listRestrictedFoldersForItemsKeys,
685
    $last_visible_parent,
686
    $last_visible_parent_level,
687
    $SETTINGS,
688
    $session_forbiden_pfs,
689
    $session_groupes_visibles,
690
    $session_list_restricted_folders_for_items,
691
    $session_user_id,
692
    $session_login,
693
    $session_user_read_only,
694
    $session_personal_folder,
695
    $session_list_folders_limited,
696
    $session_read_only_folders,
697
    $session_personal_visible_groups,
698
    $text,
699
    $nbChildrenItems,
700
    $nodeDescendants,
701
    $nodeDirectDescendants,
702
    $can_create_root_folder, 
703
    &$ret_json = array()
704
)
705
{
706
    // get info about current folder
707
    DB::query(
708
        'SELECT * FROM ' . prefixTable('items') . '
709
        WHERE inactif=%i AND id_tree = %i',
710
        0,
711
        $completTree[$nodeId]->id
712
    );
713
    $itemsNb = DB::count();
714
715
    // If personal Folder, convert id into user name
716
    if ((int) $completTree[$nodeId]->title === (int) $session_user_id && (int) $completTree[$nodeId]->nlevel === 1) {
717
        $completTree[$nodeId]->title = $session_login;
718
    }
719
720
    // Decode if needed
721
    $completTree[$nodeId]->title = htmlspecialchars_decode($completTree[$nodeId]->title, ENT_QUOTES);
722
723
    $nodeData = prepareNodeData(
724
        $completTree,
725
        (int) $completTree[$nodeId]->id,
726
        $session_groupes_visibles,
727
        $session_read_only_folders,
728
        $session_personal_visible_groups,
729
        (int) $nbChildrenItems,
730
        $nodeDescendants,
731
        (int) $itemsNb,
732
        $session_list_folders_limited,
733
        (int) $SETTINGS['show_only_accessible_folders'],
734
        $nodeDirectDescendants,
735
        isset($SETTINGS['tree_counters']) === true ? (int) $SETTINGS['tree_counters'] : '',
736
        (int) $session_user_read_only,
737
        $listFoldersLimitedKeys,
738
        $listRestrictedFoldersForItemsKeys,
739
        $session_list_restricted_folders_for_items,
740
        $session_personal_folder
741
    );
742
743
    // prepare json return for current node
744
    $parent = $completTree[$nodeId]->parent_id === '0' ? '#' : 'li_' . $completTree[$nodeId]->parent_id;
745
746
    // handle displaying
747
    if (isKeyExistingAndEqual('show_only_accessible_folders', 1, $SETTINGS) === true) {
748
        if ($nodeData['hide_node'] === true) {
749
            $last_visible_parent = (int) $parent;
750
            $last_visible_parent_level = $completTree[$nodeId]->nlevel--;
751
        } elseif ($completTree[$nodeId]->nlevel < $last_visible_parent_level) {
752
            $last_visible_parent = -1;
753
        }
754
    }
755
756
    // json
757
    if ($nodeData['hide_node'] === false && $nodeData['show_but_block'] === false) {
758
        array_push(
759
            $ret_json,
760
            array(
761
                'id' => 'li_' . $completTree[$nodeId]->id,
762
                'parent' => $last_visible_parent === -1 ? $parent : $last_visible_parent,
763
                'text' => '<i class="'.$completTree[$nodeId]->fa_icon.' tree-folder mr-2" data-folder="'.$completTree[$nodeId]->fa_icon.'"  data-folder-selected="'.$completTree[$nodeId]->fa_icon_selected.'"></i>'.$text.$completTree[$nodeId]->title.$nodeData['html'],
764
                'li_attr' => array(
765
                    'class' => 'jstreeopen',
766
                    'title' => 'ID [' . $completTree[$nodeId]->id . '] ' . $nodeData['title'],
767
                ),
768
                'a_attr' => array(
769
                    'id' => 'fld_' . $completTree[$nodeId]->id,
770
                    'class' => $nodeData['folderClass'],
771
                    'onclick' => 'ListerItems(' . $completTree[$nodeId]->id . ', ' . $nodeData['restricted'] . ', 0, 1)',
772
                    'data-title' => $completTree[$nodeId]->title,
773
                ),
774
                'is_pf' => in_array($completTree[$nodeId]->id, $session_personal_folder) === true ? 1 : 0,
775
                'can_edit' => (int) $can_create_root_folder,
776
            )
777
        );
778
    } elseif ($nodeData['show_but_block'] === true) {
779
        array_push(
780
            $ret_json,
781
            array(
782
                'id' => 'li_' . $completTree[$nodeId]->id,
783
                'parent' => $last_visible_parent === -1 ? $parent : $last_visible_parent,
784
                'text' => '<i class="'.$completTree[$nodeId]->fa_icon.' tree-folder mr-2" data-folder="'.$completTree[$nodeId]->fa_icon.'"  data-folder-selected="'.$completTree[$nodeId]->fa_icon_selected.'"></i>'.'<i class="fas fa-times fa-xs text-danger mr-1 ml-1"></i>'.$text.$completTree[$nodeId]->title.$nodeData['html'],
785
                'li_attr' => array(
786
                    'class' => '',
787
                    'title' => 'ID [' . $completTree[$nodeId]->id . '] ' . langHdl('no_access'),
788
                ),
789
            )
790
        );
791
    }
792
    
793
    foreach ($completTree[$nodeId]->children as $child) {
794
        recursiveTree(
795
            $child,
796
            $completTree,
797
            /** @scrutinizer ignore-type */ $tree,
798
            $listFoldersLimitedKeys,
799
            $listRestrictedFoldersForItemsKeys,
800
            $last_visible_parent,
801
            $last_visible_parent_level,
802
            $SETTINGS,
803
            $session_forbiden_pfs,
804
            $session_groupes_visibles,
805
            $session_list_restricted_folders_for_items,
806
            $session_user_id,
807
            $session_login,
808
            $session_user_read_only,
809
            $session_personal_folder,
810
            $session_list_folders_limited,
811
            $session_read_only_folders,
812
            $session_personal_visible_groups,
813
            $can_create_root_folder,
814
            $ret_json
815
        );
816
    }
817
}
818
819
820
821
function prepareNodeData(
822
    $completTree,
823
    $nodeId,
824
    $session_groupes_visibles,
825
    $session_read_only_folders,
826
    $session_personal_visible_groups,
827
    $nbChildrenItems,
828
    $nodeDescendants,
829
    $itemsNb,
830
    $session_list_folders_limited,
831
    $show_only_accessible_folders,
832
    $nodeDirectDescendants,
833
    $tree_counters,
834
    $session_user_read_only,
835
    $listFoldersLimitedKeys,
836
    $listRestrictedFoldersForItemsKeys,
837
    $session_list_restricted_folders_for_items,
838
    $session_personal_folder
839
): array
840
{
841
    // special case for READ-ONLY folder
842
    $title = '';
843
    if (
844
        $session_user_read_only === true
845
        && in_array($completTree[$nodeId]->id, $session_user_read_only) === false
846
    ) {
847
        $title = langHdl('read_only_account');
848
    }
849
850
    if (in_array($nodeId, $session_groupes_visibles) === true) {
851
        if (in_array($nodeId, $session_read_only_folders) === true) {
852
            return [
853
                'html' => '<i class="far fa-eye fa-xs mr-1 ml-1"></i><span class="badge badge-pill badge-light ml-2 items_count" id="itcount_' . $nodeId . '">' . $itemsNb .
854
                    ($tree_counters === 1 ? '/'.$nbChildrenItems .'/'.(count($nodeDescendants) - 1)  : '') . '</span>',
855
                'title' => langHdl('read_only_account'),
856
                'restricted' => 1,
857
                'folderClass' => 'folder_not_droppable',
858
                'show_but_block' => false,
859
                'hide_node' => false,
860
                'is_pf' => in_array($nodeId, $session_personal_folder) === true ? 1 : 0,
861
            ];
862
        }
863
864
        elseif (
865
            $session_user_read_only === true
866
            && in_array($nodeId, $session_personal_visible_groups) === false
867
        ) {
868
            return [
869
                'html' => '<i class="far fa-eye fa-xs mr-1"></i><span class="badge badge-pill badge-light ml-2 items_count" id="itcount_' . $nodeId . '">' . $itemsNb .
870
                    ($tree_counters === 1 ? '/'.$nbChildrenItems .'/'.(count($nodeDescendants) - 1)  : '') . '</span>',
871
                'title' => $title,
872
                'restricted' => 0,
873
                'folderClass' => 'folder',
874
                'show_but_block' => false,
875
                'hide_node' => false,
876
                'is_pf' => in_array($nodeId, $session_personal_folder) === true ? 1 : 0,
877
            ];
878
        }
879
        
880
        return [
881
            'html' => '<span class="badge badge-pill badge-light ml-2 items_count" id="itcount_' . $nodeId . '">' . $itemsNb .
882
                ($tree_counters === 1 ? '/'.$nbChildrenItems .'/'.(count($nodeDescendants) - 1)  : '') . '</span>',
883
            'title' => $title,
884
            'restricted' => 0,
885
            'folderClass' => 'folder',
886
            'show_but_block' => false,
887
            'hide_node' => false,
888
            'is_pf' => in_array($nodeId, $session_personal_folder) === true ? 1 : 0,
889
        ];
890
    }
891
    
892
    elseif (in_array($nodeId, $listFoldersLimitedKeys) === true) {
893
        return [
894
            'html' => ($session_user_read_only === true ? '<i class="far fa-eye fa-xs mr-1"></i>' : '') .
895
                '<span class="badge badge-pill badge-light ml-2 items_count" id="itcount_' . $nodeId . '">' . count($session_list_folders_limited[$nodeId]) . '</span>',
896
            'title' => $title,
897
            'restricted' => 1,
898
            'folderClass' => 'folder',
899
            'show_but_block' => false,
900
            'hide_node' => false,
901
            'is_pf' => in_array($nodeId, $session_personal_folder) === true ? 1 : 0,
902
        ];
903
    }
904
    
905
    elseif (in_array($nodeId, $listRestrictedFoldersForItemsKeys) === true) {
906
        return [
907
            'html' => $session_user_read_only === true ? '<i class="far fa-eye fa-xs mr-1"></i>' : '' .
908
                '<span class="badge badge-pill badge-light ml-2 items_count" id="itcount_' . $nodeId . '">' . count($session_list_restricted_folders_for_items[$nodeId]) . '</span>',
909
            'title' => $title,
910
            'restricted' => 1,
911
            'folderClass' => 'folder',
912
            'show_but_block' => false,
913
            'hide_node' => false,
914
            'is_pf' => in_array($nodeId, $session_personal_folder) === true ? 1 : 0,
915
        ];
916
    }
917
    
918
    elseif ((int) $show_only_accessible_folders === 1
919
        && (int) $nbChildrenItems === 0
920
    ) {
921
        // folder should not be visible
922
        // only if it has no descendants
923
        if (
924
            count(
925
                array_diff(
926
                    $nodeDirectDescendants,
927
                    array_merge(
928
                        $session_groupes_visibles,
929
                        array_keys($session_list_restricted_folders_for_items)
930
                    )
931
                )
932
            ) !== count($nodeDirectDescendants)
933
        ) {
934
            // show it but block it
935
            return [
936
                'html' => '',
937
                'title' => $title,
938
                'restricted' => 1,
939
                'folderClass' => 'folder_not_droppable',
940
                'show_but_block' => true,
941
                'hide_node' => false,
942
                'is_pf' => in_array($nodeId, $session_personal_folder) === true ? 1 : 0,
943
            ];
944
        }
945
        
946
        // hide it
947
        return [
948
            'html' => '',
949
            'title' => $title,
950
            'restricted' => 1,
951
            'folderClass' => 'folder_not_droppable',
952
            'show_but_block' => false,
953
            'hide_node' => true,
954
            'is_pf' => in_array($nodeId, $session_personal_folder) === true ? 1 : 0,
955
        ];
956
    }
957
958
    return [
959
        'html' => '',
960
        'title' => isset($title) === true ? $title : '',
961
        'restricted' => 1,
962
        'folderClass' => 'folder_not_droppable',
963
        'show_but_block' => true,
964
        'hide_node' => false,
965
        'is_pf' => in_array($nodeId, $session_personal_folder) === true ? 1 : 0,
966
    ];
967
}