Passed
Push — master ( 283cbf...d95a67 )
by Nils
09:38
created

buildNodeTreeElements()   C

Complexity

Conditions 15
Paths 48

Size

Total Lines 127
Code Lines 85

Duplication

Lines 0
Ratio 0 %

Importance

Changes 8
Bugs 0 Features 0
Metric Value
cc 15
eloc 85
c 8
b 0
f 0
nc 48
nop 16
dl 0
loc 127
rs 5.0606

How to fix   Long Method    Complexity    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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
include __DIR__.'/../includes/config/tp.config.php';
37
38
// includes
39
require_once $SETTINGS['cpassman_dir'] . '/includes/config/include.php';
40
require_once $SETTINGS['cpassman_dir'] . '/sources/main.functions.php';
41
require_once $SETTINGS['cpassman_dir'] . '/includes/language/' . $_SESSION['user_language'] . '.php';
42
require_once $SETTINGS['cpassman_dir'] . '/includes/config/settings.php';
43
44
// header
45
header('Content-type: text/html; charset=utf-8');
46
header('Cache-Control: no-cache, must-revalidate');
47
48
// Define Timezone
49
if (isset($SETTINGS['timezone'])) {
50
    date_default_timezone_set($SETTINGS['timezone']);
51
} else {
52
    date_default_timezone_set('UTC');
53
}
54
55
// Connect to mysql server
56
require_once $SETTINGS['cpassman_dir'] . '/includes/libraries/Database/Meekrodb/db.class.php';
57
if (defined('DB_PASSWD_CLEAR') === false) {
58
    define('DB_PASSWD_CLEAR', defuseReturnDecrypted(DB_PASSWD, $SETTINGS));
59
}
60
DB::$host = DB_HOST;
61
DB::$user = DB_USER;
62
DB::$password = DB_PASSWD_CLEAR;
63
DB::$dbName = DB_NAME;
64
DB::$port = DB_PORT;
65
DB::$encoding = DB_ENCODING;
66
DB::$ssl = DB_SSL;
67
DB::$connect_options = DB_CONNECT_OPTIONS;
68
69
// Superglobal load
70
require_once $SETTINGS['cpassman_dir'] . '/includes/libraries/protect/SuperGlobal/SuperGlobal.php';
71
$superGlobal = new protect\SuperGlobal\SuperGlobal();
72
73
// Prepare sanitization
74
$data = [
75
    'forbidenPfs' => isset($_SESSION['forbiden_pfs']) === true ? json_encode($_SESSION['forbiden_pfs']) : '{}',
76
    'visibleFolders' => isset($_SESSION['groupes_visibles']) === true ? json_encode($_SESSION['groupes_visibles']) : '{}',
77
    'userId' => isset($_SESSION['user_id']) === true ? $_SESSION['user_id'] : '',
78
    'userLogin' => isset($_SESSION['login']) === true ? $_SESSION['login'] : '',
79
    'userReadOnly' => isset($_SESSION['user_read_only']) === true ? $_SESSION['user_read_only'] : '',
80
    'limitedFolders' => isset($_SESSION['list_folders_limited']) === true ? json_encode($_SESSION['list_folders_limited']) : '{}',
81
    'readOnlyFolders' => isset($_SESSION['read_only_folders']) === true ? json_encode($_SESSION['read_only_folders']) : '{}',
82
    'personalVisibleFolders' => isset($_SESSION['personal_visible_groups']) === true ? json_encode($_SESSION['personal_visible_groups']) : '{}',
83
    'userTreeLastRefresh' => isset($_SESSION['user_tree_last_refresh_timestamp']) === true ? $_SESSION['user_tree_last_refresh_timestamp'] : '',
84
    'forceRefresh' => isset($_GET['force_refresh']) === true ? $_GET['force_refresh'] : '',
85
    'nodeId' => isset($_GET['id']) === true ? $_GET['id'] : '',
86
    'restrictedFoldersForItems' => isset($_GET['list_restricted_folders_for_items']) === true ? json_encode($_GET['list_restricted_folders_for_items']) : '{}',
87
    'noAccessFolders' => isset($_SESSION['no_access_folders']) === true ? json_encode($_SESSION['no_access_folders']) : '{}',
88
    'personalFolders' => isset($_SESSION['personal_folders']) === true ? json_encode($_SESSION['personal_folders']) : '{}',
89
    'userCanCreateRootFolder' => isset($_SESSION['can_create_root_folder']) === true ? json_encode($_SESSION['can_create_root_folder']) : '{}',
90
    'userTreeLoadStrategy' => isset($_SESSION['user']['user_treeloadstrategy']) === true ? $_SESSION['user']['user_treeloadstrategy'] : '',
91
];
92
93
$filters = [
94
    'forbidenPfs' => 'cast:array',
95
    'visibleFolders' => 'cast:array',
96
    'userId' => 'cast:integer',
97
    'userLogin' => 'trim|escape',
98
    'userReadOnly' => 'cast:boolean',
99
    'limitedFolders' => 'cast:array',
100
    'readOnlyFolders' => 'cast:array',
101
    'personalVisibleFolders' => 'cast:array',
102
    'userTreeLastRefresh' => 'cast:integer',
103
    'forceRefresh' => 'cast:integer',
104
    'nodeId' => 'cast:integer',
105
    'restrictedFoldersForItems' => 'cast:array',
106
    'noAccessFolders' => 'cast:array',
107
    'personalFolders' => 'cast:array',
108
    'userCanCreateRootFolder' => 'cast:array',
109
    'userTreeLoadStrategy' => 'trim|escape',
110
];
111
112
$inputData = dataSanitizer(
113
    $data,
114
    $filters,
115
    $SETTINGS['cpassman_dir']
116
);
117
118
$lastFolderChange = DB::queryfirstrow(
119
    'SELECT valeur FROM ' . prefixTable('misc') . '
120
    WHERE type = %s AND intitule = %s',
121
    'timestamp',
122
    'last_folder_change'
123
);
124
if (DB::count() === 0) {
125
    $lastFolderChange['valeur'] = 0;
126
}
127
128
// Should we use a cache or refresh the tree
129
$goTreeRefresh = loadTreeStrategy(
130
    (int) $lastFolderChange['valeur'],
131
    (int) $inputData['userTreeLastRefresh'],
132
    (array) (is_null($superGlobal->get('user_tree_structure', 'SESSION')) === true || empty($superGlobal->get('user_tree_structure', 'SESSION')) === true) ? [] : $superGlobal->get('user_tree_structure', 'SESSION'),
0 ignored issues
show
Bug introduced by
It seems like (array)is_null($superGlo..._structure', 'SESSION') can also be of type null; however, parameter $userSessionTreeStructure of loadTreeStrategy() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

132
    /** @scrutinizer ignore-type */ (array) (is_null($superGlobal->get('user_tree_structure', 'SESSION')) === true || empty($superGlobal->get('user_tree_structure', 'SESSION')) === true) ? [] : $superGlobal->get('user_tree_structure', 'SESSION'),
Loading history...
133
    (int) $inputData['userId'],
134
    (int) $inputData['forceRefresh']
135
);
136
137
// We don't use the cache if an ID of folder is provided
138
if ($goTreeRefresh['state'] === true || empty($inputData['nodeId']) === false || $inputData['userTreeLoadStrategy'] === 'sequential') {
139
    // Build tree
140
    require_once $SETTINGS['cpassman_dir'] . '/includes/libraries/Tree/NestedTree/NestedTree.php';
141
    $tree = new Tree\NestedTree\NestedTree(prefixTable('nested_tree'), 'id', 'parent_id', 'title');
142
143
    if (
144
        isset($inputData['limitedFolders']) === true
145
        && is_array($inputData['limitedFolders']) === true
146
        && count($inputData['limitedFolders']) > 0
147
    ) {
148
        $listFoldersLimitedKeys = array_keys($inputData['limitedFolders']);
149
    } else {
150
        $listFoldersLimitedKeys = array();
151
    }
152
    
153
    // list of items accessible but not in an allowed folder
154
    if (
155
        isset($inputData['restrictedFoldersForItems']) === true
156
        && count($inputData['restrictedFoldersForItems']) > 0
157
    ) {
158
        $listRestrictedFoldersForItemsKeys = @array_keys($inputData['restrictedFoldersForItems']);
159
    } else {
160
        $listRestrictedFoldersForItemsKeys = array();
161
    }
162
    
163
    $ret_json = array();
164
    $last_visible_parent = -1;
165
    $last_visible_parent_level = 1;
166
    $nodeId = isset($inputData['nodeId']) === true && is_int($inputData['nodeId']) === true ? $inputData['nodeId'] : 0;
167
168
    // build the tree to be displayed
169
    if (showFolderToUser(
170
        $nodeId,
171
        $inputData['forbidenPfs'],
172
        $inputData['visibleFolders'],
173
        $listFoldersLimitedKeys,
174
        $listRestrictedFoldersForItemsKeys
175
    ) === true)
176
    {
177
        if ($inputData['userTreeLoadStrategy'] === 'sequential') {
178
            // SEQUENTIAL MODE
179
            $completTree = $tree->getDescendants(empty($nodeId) === true ? '' : $nodeId, false, true, false);
0 ignored issues
show
Bug introduced by
It seems like empty($nodeId) === true ? '' : $nodeId can also be of type string; however, parameter $folder_id of Tree\NestedTree\NestedTree::getDescendants() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

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

179
            $completTree = $tree->getDescendants(/** @scrutinizer ignore-type */ empty($nodeId) === true ? '' : $nodeId, false, true, false);
Loading history...
180
            foreach ($completTree as $child) {
181
                recursiveTree(
182
                    (int) $child->id,
183
                    $child,
184
                    /** @scrutinizer ignore-type */ $tree,
185
                    $listFoldersLimitedKeys,
186
                    $listRestrictedFoldersForItemsKeys,
187
                    $last_visible_parent,
188
                    $last_visible_parent_level,
189
                    $SETTINGS,
190
                    $inputData,
191
                    $ret_json
192
                );
193
            }
194
195
        } else {
196
            // FULL MODE
197
            $completTree = $tree->getTreeWithChildren();
198
            foreach ($completTree[0]->children as $child) {
199
                recursiveTree(
200
                    (int) $child,
201
                    $completTree[$child],
202
                    /** @scrutinizer ignore-type */ $tree,
203
                    $listFoldersLimitedKeys,
204
                    $listRestrictedFoldersForItemsKeys,
205
                    $last_visible_parent,
206
                    $last_visible_parent_level,
207
                    $SETTINGS,
208
                    $inputData,
209
                    $ret_json
210
                );
211
            }
212
        }
213
    }
214
215
    // Save in SESSION
216
    $superGlobal->put('user_tree_structure', $ret_json, 'SESSION');
217
    $superGlobal->put('user_tree_last_refresh_timestamp', time(), 'SESSION');
218
219
    $ret_json = json_encode($ret_json);
220
221
    // Save user folders tree
222
    cacheTreeUserHandler(
223
        (int) $inputData['userId'],
224
        $ret_json,
225
        $SETTINGS
226
    );
227
228
    // Send back
229
    echo $ret_json;
230
} else {
231
    echo $goTreeRefresh['data'];
232
}
233
234
235
/**
236
 * Check if user can see this folder based upon rights
237
 *
238
 * @param integer $nodeId
239
 * @param array $session_forbiden_pfs
240
 * @param array $session_groupes_visibles
241
 * @param array $listFoldersLimitedKeys
242
 * @param array $listRestrictedFoldersForItemsKeys
243
 * @return boolean
244
 */
245
function showFolderToUser(
246
    int $nodeId,
247
    array $session_forbiden_pfs,
248
    array $session_groupes_visibles,
249
    array $listFoldersLimitedKeys,
250
    array $listRestrictedFoldersForItemsKeys
251
): bool
252
{
253
    $big_array = array_diff(array_unique(array_merge($session_groupes_visibles, $listFoldersLimitedKeys, $listRestrictedFoldersForItemsKeys), SORT_NUMERIC), $session_forbiden_pfs);
254
    //print_r($session_groupes_visibles);
255
    if (
256
        in_array($nodeId, $big_array) === true) {
257
        return true;
258
    }
259
    return false;
260
}
261
262
263
/**
264
 * Get some infos for this node
265
 *
266
 * @param integer   $nodeId
267
 * @param integer   $nodeLevel
268
 * @param string    $nodeTitle
269
 * @param integer   $userId
270
 * @param string    $userLogin
271
 * @param bool      $userIsRO
272
 * @param array     $userPF
273
 * @return array
274
 */
275
function getNodeInfos(
276
    int $nodeId,
277
    int $nodeLevel,
278
    string $nodeTitle,
279
    int $userId,
280
    string $userLogin,
281
    bool $userIsRO,
282
    array $userPF
283
) : array
284
{
285
    $ret = [];
286
    // get count of Items in this folder
287
    DB::query(
288
        'SELECT *
289
        FROM ' . prefixTable('items') . '
290
        WHERE inactif=%i AND id_tree = %i',
291
        0,
292
        $nodeId
293
    );
294
    $ret['itemsNb'] = DB::count();
295
296
    // get info about current folder
297
    DB::query(
298
        'SELECT *
299
        FROM ' . prefixTable('nested_tree') . '
300
        WHERE parent_id = %i',
301
        $nodeId
302
    );
303
    $ret['childrenNb'] = DB::count();
304
305
    // Manage node title
306
    if ($userIsRO === true && in_array($nodeId, $userPF) === false) {
307
        // special case for READ-ONLY folder
308
        $ret['title'] = langHdl('read_only_account');
309
    } else {
310
        // If personal Folder, convert id into user name
311
        $ret['title'] = (string) $nodeTitle === (string) $userId && (int) $nodeLevel === 1 ?
312
        $userLogin :
313
        htmlspecialchars_decode($nodeTitle, ENT_QUOTES);
314
    }
315
316
    $ret['text'] = str_replace(
317
        '&',
318
        '&amp;',
319
        $ret['title']
320
    );
321
322
    return $ret;
323
}
324
325
326
/**
327
 * Get through complete tree
328
 *
329
 * @param int     $nodeId                            Id
330
 * @param stdClass   $currentNode                       Tree info
331
 * @param Tree\NestedTree\NestedTree   $tree                              The tree
332
 * @param array   $listFoldersLimitedKeys            Limited
333
 * @param array   $listRestrictedFoldersForItemsKeys Restricted
334
 * @param int     $last_visible_parent               Visible parent
335
 * @param int     $last_visible_parent_level         Parent level
336
 * @param array   $SETTINGS                          Teampass settings
337
 * @param array   $inputData,
338
 * @param array   $ret_json
339
 *
340
 * @return array
341
 */
342
function recursiveTree(
343
    int $nodeId,
344
    stdClass $currentNode,
345
    Tree\NestedTree\NestedTree $tree,
346
    array $listFoldersLimitedKeys,
347
    array $listRestrictedFoldersForItemsKeys,
348
    int $last_visible_parent,
349
    int $last_visible_parent_level,
350
    array $SETTINGS,
351
    array $inputData,
352
    array &$ret_json = array()
353
) {
354
    $text = '';
355
    $title = '';
356
    $show_but_block = false;
357
    
358
    // Load config
359
    include __DIR__.'/../includes/config/tp.config.php';
360
361
362
    // Be sure that user can only see folders he/she is allowed to
363
    if (
364
        //in_array($nodeId, $session_forbiden_pfs) === false
365
        //|| in_array($nodeId, $session_groupes_visibles) === true
366
        in_array($nodeId, array_merge($inputData['personalFolders'], $inputData['visibleFolders'])) === true
367
    ) {
368
        $displayThisNode = false;
369
        $nbChildrenItems = 0;
370
        $nodeDescendants = $nodeDirectDescendants = $tree->getDescendants($nodeId, true, false, true);
371
        array_shift($nodeDirectDescendants); // get only the children
372
373
        // Check if any allowed folder is part of the descendants of this node
374
        foreach ($nodeDescendants as $node) {
375
            // manage tree counters
376
            if (
377
                isKeyExistingAndEqual('tree_counters', 1, $SETTINGS) === true
378
                && in_array(
379
                    $node,
380
                    array_merge(
381
                        $inputData['visibleFolders'],
382
                        is_null($inputData['restrictedFoldersForItems']) === true ? [] : $inputData['restrictedFoldersForItems']
383
                    )
384
                ) === true
385
            ) {
386
                DB::query(
387
                    'SELECT * FROM ' . prefixTable('items') . '
388
                    WHERE inactif=%i AND id_tree = %i',
389
                    0,
390
                    $node
391
                );
392
                $nbChildrenItems += DB::count();
393
            }
394
395
            if (
396
                in_array($node, array_merge($inputData['personalFolders'], $inputData['visibleFolders'])) === true
397
            ) {
398
                // Final check - is PF allowed?
399
                $nodeDetails = $tree->getNode($node);
400
                if (
401
                    (int) $nodeDetails->personal_folder === 1
402
                    && (int) $SETTINGS['enable_pf_feature'] === 1
403
                    && in_array($node, $inputData['personalFolders']) === false
404
                ) {
405
                    $displayThisNode = false;
406
                } else {
407
                    $displayThisNode = true;
408
                    // not adding a break in order to permit a correct count of items
409
                }
410
                $text = '';
411
            }
412
        }
413
        
414
        if ($displayThisNode === true) {
415
            handleNode(
416
                (int) $nodeId,
417
                $currentNode,
418
                $tree,
419
                $listFoldersLimitedKeys,
420
                $listRestrictedFoldersForItemsKeys,
421
                $last_visible_parent,
422
                $last_visible_parent_level,
423
                $SETTINGS,
424
                $inputData,
425
                $text,
426
                $nbChildrenItems,
427
                $nodeDescendants,
428
                $nodeDirectDescendants,
429
                $ret_json
430
            );
431
        }
432
    }
433
    return $ret_json;
434
}
435
436
/**
437
 * Permits to get the Node definition
438
 *
439
 * @param integer $nodeId
440
 * @param stdClass $currentNode
441
 * @param Tree\NestedTree\NestedTree $tree
442
 * @param array $listFoldersLimitedKeys
443
 * @param array $listRestrictedFoldersForItemsKeys
444
 * @param integer $last_visible_parent
445
 * @param integer $last_visible_parent_level
446
 * @param array $SETTINGS
447
 * @param array $inputData
448
 * @param string $text
449
 * @param integer $nbChildrenItems
450
 * @param array $nodeDescendants
451
 * @param array $nodeDirectDescendants
452
 * @param array $ret_json
453
 * @return void
454
 */
455
function handleNode(
456
    int $nodeId,
457
    stdClass $currentNode,
458
    Tree\NestedTree\NestedTree $tree,
459
    array $listFoldersLimitedKeys,
460
    array $listRestrictedFoldersForItemsKeys,
461
    int $last_visible_parent,
462
    int $last_visible_parent_level,
463
    array $SETTINGS,
464
    array $inputData,
465
    string $text,
466
    int $nbChildrenItems,
467
    array $nodeDescendants,
468
    array $nodeDirectDescendants,
469
    array &$ret_json = array()
470
)
471
{
472
    // get info about current folder
473
    DB::query(
474
        'SELECT * FROM ' . prefixTable('items') . '
475
        WHERE inactif=%i AND id_tree = %i',
476
        0,
477
        $nodeId
478
    );
479
    $itemsNb = DB::count();
480
481
    // If personal Folder, convert id into user name
482
    if ((int) $currentNode->title === (int) $inputData['userId'] && (int) $currentNode->nlevel === 1) {
483
        $currentNode->title = $inputData['userLogin'];
484
    }
485
486
    // Decode if needed
487
    $currentNode->title = htmlspecialchars_decode($currentNode->title, ENT_QUOTES);
488
489
    $nodeData = prepareNodeData(
490
        $currentNode,
491
        (int) $nodeId,
492
        $inputData['visibleFolders'],
493
        $inputData['readOnlyFolders'],
494
        $inputData['personalVisibleFolders'],
495
        (int) $nbChildrenItems,
496
        $nodeDescendants,
497
        (int) $itemsNb,
498
        $inputData['limitedFolders'],
499
        (int) $SETTINGS['show_only_accessible_folders'],
500
        $nodeDirectDescendants,
501
        isset($SETTINGS['tree_counters']) === true ? (int) $SETTINGS['tree_counters'] : '',
0 ignored issues
show
Bug introduced by
It seems like IssetNode === true ? (in...S['tree_counters'] : '' can also be of type string; however, parameter $tree_counters of prepareNodeData() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

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

501
        /** @scrutinizer ignore-type */ isset($SETTINGS['tree_counters']) === true ? (int) $SETTINGS['tree_counters'] : '',
Loading history...
502
        (int) $inputData['userReadOnly'],
503
        $listFoldersLimitedKeys,
504
        $listRestrictedFoldersForItemsKeys,
505
        $inputData['restrictedFoldersForItems'],
506
        $inputData['personalFolders']
507
    );
508
509
    // prepare json return for current node
510
    $parent = $currentNode->parent_id === '0' ? '#' : 'li_' . $currentNode->parent_id;
511
512
    // handle displaying
513
    if (isKeyExistingAndEqual('show_only_accessible_folders', 1, $SETTINGS) === true) {
514
        if ($nodeData['hide_node'] === true) {
515
            $last_visible_parent = (int) $parent;
516
            $last_visible_parent_level = $currentNode->nlevel--;
517
        } elseif ($currentNode->nlevel < $last_visible_parent_level) {
518
            $last_visible_parent = -1;
519
        }
520
    }
521
522
    // json
523
    if ($nodeData['hide_node'] === false && $nodeData['show_but_block'] === false) {
524
        array_push(
525
            $ret_json,
526
            array(
527
                'id' => 'li_' . $nodeId,
528
                'parent' => $last_visible_parent === -1 ? $parent : $last_visible_parent,
529
                'text' => '<i class="'.$currentNode->fa_icon.' tree-folder mr-2" data-folder="'.$currentNode->fa_icon.'"  data-folder-selected="'.$currentNode->fa_icon_selected.'"></i>'.$text.$currentNode->title.$nodeData['html'],
530
                'li_attr' => array(
531
                    'class' => 'jstreeopen',
532
                    'title' => 'ID [' . $nodeId . '] ' . $nodeData['title'],
533
                ),
534
                'a_attr' => array(
535
                    'id' => 'fld_' . $nodeId,
536
                    'class' => $nodeData['folderClass'],
537
                    'onclick' => 'ListerItems(' . $nodeId . ', ' . $nodeData['restricted'] . ', 0, 1)',
538
                    'data-title' => $currentNode->title,
539
                ),
540
                'is_pf' => in_array($nodeId, $inputData['personalFolders']) === true ? 1 : 0,
541
                'can_edit' => (int) $inputData['userCanCreateRootFolder'],
542
                //'children' => count($nodeDirectDescendants) > 0 ? true : false,
543
            )
544
        );
545
        
546
        if ($inputData['userTreeLoadStrategy'] === 'sequential') {
547
            //print_r($ret_json[count($ret_json) - 1]);
548
            //array_push($ret_json[count($ret_json) - 1], array('children' => count($nodeDirectDescendants) > 0 ? true : false,));
549
            $ret_json[count($ret_json) - 1]['children'] = count($nodeDirectDescendants) > 0 ? true : false;
550
        }
551
552
    } elseif ($nodeData['show_but_block'] === true) {
553
        array_push(
554
            $ret_json,
555
            array(
556
                'id' => 'li_' . $nodeId,
557
                'parent' => $last_visible_parent === -1 ? $parent : $last_visible_parent,
558
                'text' => '<i class="'.$currentNode->fa_icon.' tree-folder mr-2" data-folder="'.$currentNode->fa_icon.'"  data-folder-selected="'.$currentNode->fa_icon_selected.'"></i>'.'<i class="fas fa-times fa-xs text-danger mr-1 ml-1"></i>'.$text.$currentNode->title.$nodeData['html'],
559
                'li_attr' => array(
560
                    'class' => '',
561
                    'title' => 'ID [' . $nodeId . '] ' . langHdl('no_access'),
562
                ),
563
            )
564
        );
565
    }
566
567
    // ensure we get the children of the folder
568
    if (isset($currentNode->children) === false) {
569
        $currentNode->children = $tree->getDescendants($nodeId, false, true, true);
570
    }
571
    if ($inputData['userTreeLoadStrategy'] === 'full' && isset($currentNode->children) === true) {
572
        foreach ($currentNode->children as $child) {
573
            recursiveTree(
574
                (int) $child,
575
                $tree->getNode($child),// get node info for this child
576
                /** @scrutinizer ignore-type */ $tree,
577
                $listFoldersLimitedKeys,
578
                $listRestrictedFoldersForItemsKeys,
579
                $last_visible_parent,
580
                $last_visible_parent_level,
581
                $SETTINGS,
582
                $inputData,
583
                $ret_json
584
            );
585
        }
586
    }
587
}
588
589
/**
590
 * Get the context of the folder
591
 *
592
 * @param stdClass $completTree
593
 * @param integer $nodeId
594
 * @param array $session_groupes_visibles
595
 * @param array $session_read_only_folders
596
 * @param array $session_personal_visible_groups
597
 * @param integer $nbChildrenItems
598
 * @param array $nodeDescendants
599
 * @param integer $itemsNb
600
 * @param array $session_list_folders_limited
601
 * @param integer $show_only_accessible_folders
602
 * @param array $nodeDirectDescendants
603
 * @param integer $tree_counters
604
 * @param integer $session_user_read_only
605
 * @param array $listFoldersLimitedKeys
606
 * @param array $listRestrictedFoldersForItemsKeys
607
 * @param array $session_list_restricted_folders_for_items
608
 * @param array $session_personal_folder
609
 * @return array
610
 */
611
function prepareNodeData(
612
    stdClass $completTree,
613
    int $nodeId,
614
    array $session_groupes_visibles,
615
    array $session_read_only_folders,
616
    array $session_personal_visible_groups,
617
    int $nbChildrenItems,
618
    array $nodeDescendants,
619
    int $itemsNb,
620
    array $session_list_folders_limited,
621
    int $show_only_accessible_folders,
622
    array $nodeDirectDescendants,
623
    int $tree_counters,
624
    int $session_user_read_only,
625
    array $listFoldersLimitedKeys,
626
    array $listRestrictedFoldersForItemsKeys,
627
    array $session_list_restricted_folders_for_items,
628
    array $session_personal_folder
629
): array
630
{
631
    // special case for READ-ONLY folder
632
    $title = '';
633
    if (
634
        $session_user_read_only === true
0 ignored issues
show
introduced by
The condition $session_user_read_only === true is always false.
Loading history...
635
        && in_array($completTree[$nodeId]->id, $session_user_read_only) === false
0 ignored issues
show
Bug introduced by
$session_user_read_only of type integer is incompatible with the type array expected by parameter $haystack of in_array(). ( Ignorable by Annotation )

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

635
        && in_array($completTree[$nodeId]->id, /** @scrutinizer ignore-type */ $session_user_read_only) === false
Loading history...
636
    ) {
637
        $title = langHdl('read_only_account');
638
    }
639
640
    if (in_array($nodeId, $session_groupes_visibles) === true) {
641
        if (in_array($nodeId, $session_read_only_folders) === true) {
642
            return [
643
                '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 .
644
                    ($tree_counters === 1 ? '/'.$nbChildrenItems .'/'.(count($nodeDescendants) - 1)  : '') . '</span>',
645
                'title' => langHdl('read_only_account'),
646
                'restricted' => 1,
647
                'folderClass' => 'folder_not_droppable',
648
                'show_but_block' => false,
649
                'hide_node' => false,
650
                'is_pf' => in_array($nodeId, $session_personal_folder) === true ? 1 : 0,
651
            ];
652
653
        } elseif (
654
            $session_user_read_only === true
0 ignored issues
show
introduced by
The condition $session_user_read_only === true is always false.
Loading history...
655
            && in_array($nodeId, $session_personal_visible_groups) === false
656
        ) {
657
            return [
658
                '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 .
659
                    ($tree_counters === 1 ? '/'.$nbChildrenItems .'/'.(count($nodeDescendants) - 1)  : '') . '</span>',
660
                'title' => $title,
661
                'restricted' => 0,
662
                'folderClass' => 'folder',
663
                'show_but_block' => false,
664
                'hide_node' => false,
665
                'is_pf' => in_array($nodeId, $session_personal_folder) === true ? 1 : 0,
666
            ];
667
        }
668
        
669
        return [
670
            'html' => '<span class="badge badge-pill badge-light ml-2 items_count" id="itcount_' . $nodeId . '">' . $itemsNb .
671
                ($tree_counters === 1 ? '/'.$nbChildrenItems .'/'.(count($nodeDescendants) - 1)  : '') . '</span>',
672
            'title' => $title,
673
            'restricted' => 0,
674
            'folderClass' => 'folder',
675
            'show_but_block' => false,
676
            'hide_node' => false,
677
            'is_pf' => in_array($nodeId, $session_personal_folder) === true ? 1 : 0,
678
        ];
679
680
    } elseif (in_array($nodeId, $listFoldersLimitedKeys) === true) {
681
        return [
682
            'html' => ($session_user_read_only === true ? '<i class="far fa-eye fa-xs mr-1"></i>' : '') .
0 ignored issues
show
introduced by
The condition $session_user_read_only === true is always false.
Loading history...
683
                '<span class="badge badge-pill badge-light ml-2 items_count" id="itcount_' . $nodeId . '">' . count($session_list_folders_limited[$nodeId]) . '</span>',
684
            'title' => $title,
685
            'restricted' => 1,
686
            'folderClass' => 'folder',
687
            'show_but_block' => false,
688
            'hide_node' => false,
689
            'is_pf' => in_array($nodeId, $session_personal_folder) === true ? 1 : 0,
690
        ];
691
692
    } elseif (in_array($nodeId, $listRestrictedFoldersForItemsKeys) === true) {
693
        return [
694
            'html' => $session_user_read_only === true ? '<i class="far fa-eye fa-xs mr-1"></i>' : '' .
0 ignored issues
show
introduced by
The condition $session_user_read_only === true is always false.
Loading history...
695
                '<span class="badge badge-pill badge-light ml-2 items_count" id="itcount_' . $nodeId . '">' . count($session_list_restricted_folders_for_items[$nodeId]) . '</span>',
696
            'title' => $title,
697
            'restricted' => 1,
698
            'folderClass' => 'folder',
699
            'show_but_block' => false,
700
            'hide_node' => false,
701
            'is_pf' => in_array($nodeId, $session_personal_folder) === true ? 1 : 0,
702
        ];
703
704
    } elseif ((int) $show_only_accessible_folders === 1
705
        && (int) $nbChildrenItems === 0
706
    ) {
707
        // folder should not be visible
708
        // only if it has no descendants
709
        if (
710
            count(
711
                array_diff(
712
                    $nodeDirectDescendants,
713
                    array_merge(
714
                        $session_groupes_visibles,
715
                        array_keys($session_list_restricted_folders_for_items)
716
                    )
717
                )
718
            ) !== count($nodeDirectDescendants)
719
        ) {
720
            // show it but block it
721
            return [
722
                'html' => '',
723
                'title' => $title,
724
                'restricted' => 1,
725
                'folderClass' => 'folder_not_droppable',
726
                'show_but_block' => true,
727
                'hide_node' => false,
728
                'is_pf' => in_array($nodeId, $session_personal_folder) === true ? 1 : 0,
729
            ];
730
        }
731
        
732
        // hide it
733
        return [
734
            'html' => '',
735
            'title' => $title,
736
            'restricted' => 1,
737
            'folderClass' => 'folder_not_droppable',
738
            'show_but_block' => false,
739
            'hide_node' => true,
740
            'is_pf' => in_array($nodeId, $session_personal_folder) === true ? 1 : 0,
741
        ];
742
    }
743
744
    return [
745
        'html' => '',
746
        'title' => isset($title) === true ? $title : '',
747
        'restricted' => 1,
748
        'folderClass' => 'folder_not_droppable',
749
        'show_but_block' => true,
750
        'hide_node' => false,
751
        'is_pf' => in_array($nodeId, $session_personal_folder) === true ? 1 : 0,
752
    ];
753
}
754
755
756
/**
757
 * Permits to check if we can user a cache instead of loading from DB
758
 *
759
 * @param integer $lastTreeChange
760
 * @param integer $userTreeLastRefresh
761
 * @param array $userSessionTreeStructure
762
 * @param integer $userId
763
 * @param integer $forceRefresh
764
 * @param array $SETTINGS
765
 * @return array
766
 */
767
function loadTreeStrategy(
768
    int $lastTreeChange,
769
    int $userTreeLastRefresh,
770
    array $userSessionTreeStructure,
771
    int $userId,
772
    int $forceRefresh
773
): array
774
{
775
    // Case when refresh is EXPECTED / MANDATORY
776
    if ((int) $forceRefresh === 1) {
777
        return [
778
            'state' => true,
779
            'data' => [],
780
        ];
781
    }
782
783
    // Case when an update in the tree has been done
784
    // Refresh is then mandatory
785
    if ((int) $lastTreeChange > (int) $userTreeLastRefresh) {
786
        return [
787
            'state' => true,
788
            'data' => [],
789
        ];
790
    }
791
792
    // Does this user has the tree structure in session?
793
    // If yes then use it
794
    if (count($userSessionTreeStructure) > 0) {
795
        return [
796
            'state' => false,
797
            'data' => json_encode($userSessionTreeStructure),
798
        ];
799
    }
800
801
    // Does this user has a tree cache
802
    $userCacheTree = DB::queryfirstrow(
803
        'SELECT data
804
        FROM ' . prefixTable('cache_tree') . '
805
        WHERE user_id = %i',
806
        $userId
807
    );
808
    if (empty($userCacheTree['data']) === false && $userCacheTree['data'] !== '[]') {
809
        return [
810
            'state' => false,
811
            'data' => $userCacheTree['data'],
812
        ];
813
    }
814
815
    return [
816
        'state' => true,
817
        'data' => [],
818
    ];
819
}