Passed
Push — master ( b55dbf...d66e0a )
by Nils
09:04
created

recursiveTree()   B

Complexity

Conditions 10
Paths 14

Size

Total Lines 85
Code Lines 49

Duplication

Lines 0
Ratio 0 %

Importance

Changes 18
Bugs 2 Features 0
Metric Value
cc 10
eloc 49
c 18
b 2
f 0
nc 14
nop 10
dl 0
loc 85
rs 7.246

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 ? 0 : (int) $nodeId, false, true, false);
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 ($nodeId === 0 || in_array($nodeId, $big_array) === true) {
256
        return true;
257
    }
258
    return false;
259
}
260
261
262
/**
263
 * Get some infos for this node
264
 *
265
 * @param integer   $nodeId
266
 * @param integer   $nodeLevel
267
 * @param string    $nodeTitle
268
 * @param integer   $userId
269
 * @param string    $userLogin
270
 * @param bool      $userIsRO
271
 * @param array     $userPF
272
 * @return array
273
 */
274
function getNodeInfos(
275
    int $nodeId,
276
    int $nodeLevel,
277
    string $nodeTitle,
278
    int $userId,
279
    string $userLogin,
280
    bool $userIsRO,
281
    array $userPF
282
) : array
283
{
284
    $ret = [];
285
    // get count of Items in this folder
286
    DB::query(
287
        'SELECT *
288
        FROM ' . prefixTable('items') . '
289
        WHERE inactif=%i AND id_tree = %i',
290
        0,
291
        $nodeId
292
    );
293
    $ret['itemsNb'] = DB::count();
294
295
    // get info about current folder
296
    DB::query(
297
        'SELECT *
298
        FROM ' . prefixTable('nested_tree') . '
299
        WHERE parent_id = %i',
300
        $nodeId
301
    );
302
    $ret['childrenNb'] = DB::count();
303
304
    // Manage node title
305
    if ($userIsRO === true && in_array($nodeId, $userPF) === false) {
306
        // special case for READ-ONLY folder
307
        $ret['title'] = langHdl('read_only_account');
308
    } else {
309
        // If personal Folder, convert id into user name
310
        $ret['title'] = (string) $nodeTitle === (string) $userId && (int) $nodeLevel === 1 ?
311
        $userLogin :
312
        htmlspecialchars_decode($nodeTitle, ENT_QUOTES);
313
    }
314
315
    $ret['text'] = str_replace(
316
        '&',
317
        '&amp;',
318
        $ret['title']
319
    );
320
321
    return $ret;
322
}
323
324
325
/**
326
 * Get through complete tree
327
 *
328
 * @param int     $nodeId                            Id
329
 * @param stdClass   $currentNode                       Tree info
330
 * @param Tree\NestedTree\NestedTree   $tree                              The tree
331
 * @param array   $listFoldersLimitedKeys            Limited
332
 * @param array   $listRestrictedFoldersForItemsKeys Restricted
333
 * @param int     $last_visible_parent               Visible parent
334
 * @param int     $last_visible_parent_level         Parent level
335
 * @param array   $SETTINGS                          Teampass settings
336
 * @param array   $inputData,
337
 * @param array   $ret_json
338
 *
339
 * @return array
340
 */
341
function recursiveTree(
342
    int $nodeId,
343
    stdClass $currentNode,
344
    Tree\NestedTree\NestedTree $tree,
345
    array $listFoldersLimitedKeys,
346
    array $listRestrictedFoldersForItemsKeys,
347
    int $last_visible_parent,
348
    int $last_visible_parent_level,
349
    array $SETTINGS,
350
    array $inputData,
351
    array &$ret_json = array()
352
) {
353
    $text = '';
354
    $title = '';
355
    $show_but_block = false;
356
    
357
    // Load config
358
    include __DIR__.'/../includes/config/tp.config.php';
359
360
    $displayThisNode = false;
361
    $nbChildrenItems = 0;
362
    $nodeDescendants = $nodeDirectDescendants = $tree->getDescendants($nodeId, true, false, true);
363
    array_shift($nodeDirectDescendants); // get only the children
364
365
    // Check if any allowed folder is part of the descendants of this node
366
    foreach ($nodeDescendants as $node) {
367
        // manage tree counters
368
        if (
369
            isKeyExistingAndEqual('tree_counters', 1, $SETTINGS) === true
370
            && in_array(
371
                $node,
372
                array_merge(
373
                    $inputData['visibleFolders'],
374
                    is_null($inputData['restrictedFoldersForItems']) === true ? [] : $inputData['restrictedFoldersForItems']
375
                )
376
            ) === true
377
        ) {
378
            DB::query(
379
                'SELECT * FROM ' . prefixTable('items') . '
380
                WHERE inactif=%i AND id_tree = %i',
381
                0,
382
                $node
383
            );
384
            $nbChildrenItems += DB::count();
385
        }
386
387
        if (
388
            in_array($node, array_merge($inputData['personalFolders'], $inputData['visibleFolders'])) === true
389
        ) {
390
            // Final check - is PF allowed?
391
            $nodeDetails = $tree->getNode($node);
392
            if (
393
                (int) $nodeDetails->personal_folder === 1
394
                && (int) $SETTINGS['enable_pf_feature'] === 1
395
                && in_array($node, $inputData['personalFolders']) === false
396
            ) {
397
                $displayThisNode = false;
398
            } else {
399
                $displayThisNode = true;
400
                // not adding a break in order to permit a correct count of items
401
            }
402
            $text = '';
403
        }
404
    }
405
    
406
    if ($displayThisNode === true) {
407
        handleNode(
408
            (int) $nodeId,
409
            $currentNode,
410
            $tree,
411
            $listFoldersLimitedKeys,
412
            $listRestrictedFoldersForItemsKeys,
413
            $last_visible_parent,
414
            $last_visible_parent_level,
415
            $SETTINGS,
416
            $inputData,
417
            $text,
418
            $nbChildrenItems,
419
            $nodeDescendants,
420
            $nodeDirectDescendants,
421
            $ret_json
422
        );
423
    }
424
    
425
    return $ret_json;
426
}
427
428
/**
429
 * Permits to get the Node definition
430
 *
431
 * @param integer $nodeId
432
 * @param stdClass $currentNode
433
 * @param Tree\NestedTree\NestedTree $tree
434
 * @param array $listFoldersLimitedKeys
435
 * @param array $listRestrictedFoldersForItemsKeys
436
 * @param integer $last_visible_parent
437
 * @param integer $last_visible_parent_level
438
 * @param array $SETTINGS
439
 * @param array $inputData
440
 * @param string $text
441
 * @param integer $nbChildrenItems
442
 * @param array $nodeDescendants
443
 * @param array $nodeDirectDescendants
444
 * @param array $ret_json
445
 * @return void
446
 */
447
function handleNode(
448
    int $nodeId,
449
    stdClass $currentNode,
450
    Tree\NestedTree\NestedTree $tree,
451
    array $listFoldersLimitedKeys,
452
    array $listRestrictedFoldersForItemsKeys,
453
    int $last_visible_parent,
454
    int $last_visible_parent_level,
455
    array $SETTINGS,
456
    array $inputData,
457
    string $text,
458
    int $nbChildrenItems,
459
    array $nodeDescendants,
460
    array $nodeDirectDescendants,
461
    array &$ret_json = array()
462
)
463
{
464
    // get info about current folder
465
    DB::query(
466
        'SELECT * FROM ' . prefixTable('items') . '
467
        WHERE inactif=%i AND id_tree = %i',
468
        0,
469
        $nodeId
470
    );
471
    $itemsNb = DB::count();
472
473
    // If personal Folder, convert id into user name
474
    if ((int) $currentNode->title === (int) $inputData['userId'] && (int) $currentNode->nlevel === 1) {
475
        $currentNode->title = $inputData['userLogin'];
476
    }
477
478
    // Decode if needed
479
    $currentNode->title = htmlspecialchars_decode($currentNode->title, ENT_QUOTES);
480
481
    $nodeData = prepareNodeData(
482
        $currentNode,
483
        (int) $nodeId,
484
        $inputData['visibleFolders'],
485
        $inputData['readOnlyFolders'],
486
        $inputData['personalVisibleFolders'],
487
        (int) $nbChildrenItems,
488
        $nodeDescendants,
489
        (int) $itemsNb,
490
        $inputData['limitedFolders'],
491
        (int) $SETTINGS['show_only_accessible_folders'],
492
        $nodeDirectDescendants,
493
        isset($SETTINGS['tree_counters']) === true ? (int) $SETTINGS['tree_counters'] : 0,
494
        (bool) $inputData['userReadOnly'],
495
        $listFoldersLimitedKeys,
496
        $listRestrictedFoldersForItemsKeys,
497
        $inputData['restrictedFoldersForItems'],
498
        $inputData['personalFolders']
499
    );
500
501
    // prepare json return for current node
502
    $parent = $currentNode->parent_id === '0' ? '#' : 'li_' . $currentNode->parent_id;
503
504
    // handle displaying
505
    if (isKeyExistingAndEqual('show_only_accessible_folders', 1, $SETTINGS) === true) {
506
        if ($nodeData['hide_node'] === true) {
507
            $last_visible_parent = (int) $parent;
508
            $last_visible_parent_level = $currentNode->nlevel--;
509
        } elseif ($currentNode->nlevel < $last_visible_parent_level) {
510
            $last_visible_parent = -1;
511
        }
512
    }
513
514
    // json
515
    if ($nodeData['hide_node'] === false && $nodeData['show_but_block'] === false) {
516
        array_push(
517
            $ret_json,
518
            array(
519
                'id' => 'li_' . $nodeId,
520
                'parent' => $last_visible_parent === -1 ? $parent : $last_visible_parent,
521
                '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'],
522
                'li_attr' => array(
523
                    'class' => 'jstreeopen',
524
                    'title' => 'ID [' . $nodeId . '] ' . $nodeData['title'],
525
                ),
526
                'a_attr' => array(
527
                    'id' => 'fld_' . $nodeId,
528
                    'class' => $nodeData['folderClass'],
529
                    'onclick' => 'ListerItems(' . $nodeId . ', ' . $nodeData['restricted'] . ', 0, 1)',
530
                    'data-title' => $currentNode->title,
531
                ),
532
                'is_pf' => in_array($nodeId, $inputData['personalFolders']) === true ? 1 : 0,
533
                'can_edit' => (int) $inputData['userCanCreateRootFolder'],
534
                //'children' => count($nodeDirectDescendants) > 0 ? true : false,
535
            )
536
        );
537
        
538
        if ($inputData['userTreeLoadStrategy'] === 'sequential') {
539
            $ret_json[count($ret_json) - 1]['children'] = count($nodeDirectDescendants) > 0 ? true : false;
540
        }
541
542
    } elseif ($nodeData['show_but_block'] === true) {
543
        array_push(
544
            $ret_json,
545
            array(
546
                'id' => 'li_' . $nodeId,
547
                'parent' => $last_visible_parent === -1 ? $parent : $last_visible_parent,
548
                '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'],
549
                'li_attr' => array(
550
                    'class' => '',
551
                    'title' => 'ID [' . $nodeId . '] ' . langHdl('no_access'),
552
                ),
553
            )
554
        );
555
    }
556
557
    // ensure we get the children of the folder
558
    if (isset($currentNode->children) === false) {
559
        $currentNode->children = $tree->getDescendants($nodeId, false, true, true);
560
    }
561
    if ($inputData['userTreeLoadStrategy'] === 'full' && isset($currentNode->children) === true) {
562
        foreach ($currentNode->children as $child) {
563
            recursiveTree(
564
                (int) $child,
565
                $tree->getNode($child),// get node info for this child
566
                /** @scrutinizer ignore-type */ $tree,
567
                $listFoldersLimitedKeys,
568
                $listRestrictedFoldersForItemsKeys,
569
                $last_visible_parent,
570
                $last_visible_parent_level,
571
                $SETTINGS,
572
                $inputData,
573
                $ret_json
574
            );
575
        }
576
    }
577
}
578
579
/**
580
 * Get the context of the folder
581
 *
582
 * @param stdClass $completTree
583
 * @param integer $nodeId
584
 * @param array $session_groupes_visibles
585
 * @param array $session_read_only_folders
586
 * @param array $session_personal_visible_groups
587
 * @param integer $nbChildrenItems
588
 * @param array $nodeDescendants
589
 * @param integer $itemsNb
590
 * @param array $session_list_folders_limited
591
 * @param integer $show_only_accessible_folders
592
 * @param array $nodeDirectDescendants
593
 * @param integer $tree_counters
594
 * @param bool $session_user_read_only
595
 * @param array $listFoldersLimitedKeys
596
 * @param array $listRestrictedFoldersForItemsKeys
597
 * @param array $session_list_restricted_folders_for_items
598
 * @param array $session_personal_folder
599
 * @return array
600
 */
601
function prepareNodeData(
602
    stdClass $completTree,
603
    int $nodeId,
604
    array $session_groupes_visibles,
605
    array $session_read_only_folders,
606
    array $session_personal_visible_groups,
607
    int $nbChildrenItems,
608
    array $nodeDescendants,
609
    int $itemsNb,
610
    array $session_list_folders_limited,
611
    int $show_only_accessible_folders,
612
    array $nodeDirectDescendants,
613
    int $tree_counters,
614
    bool $session_user_read_only,
615
    array $listFoldersLimitedKeys,
616
    array $listRestrictedFoldersForItemsKeys,
617
    array $session_list_restricted_folders_for_items,
618
    array $session_personal_folder
619
): array
620
{
621
    // special case for READ-ONLY folder
622
    $title = '';
623
    if (
624
        $session_user_read_only === true
625
        || in_array((int) $completTree->id, $session_read_only_folders) === false
626
    ) {
627
        $title = langHdl('read_only_account');
628
    }
629
630
    if (in_array($nodeId, $session_groupes_visibles) === true) {
631
        if (in_array($nodeId, $session_read_only_folders) === true) {
632
            return [
633
                '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 .
634
                    ($tree_counters === 1 ? '/'.$nbChildrenItems .'/'.(count($nodeDescendants) - 1)  : '') . '</span>',
635
                'title' => langHdl('read_only_account'),
636
                'restricted' => 1,
637
                'folderClass' => 'folder_not_droppable',
638
                'show_but_block' => false,
639
                'hide_node' => false,
640
                'is_pf' => in_array($nodeId, $session_personal_folder) === true ? 1 : 0,
641
            ];
642
643
        } elseif (
644
            $session_user_read_only === true
645
            && in_array($nodeId, $session_personal_visible_groups) === false
646
        ) {
647
            return [
648
                '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 .
649
                    ($tree_counters === 1 ? '/'.$nbChildrenItems .'/'.(count($nodeDescendants) - 1)  : '') . '</span>',
650
                'title' => $title,
651
                'restricted' => 0,
652
                'folderClass' => 'folder',
653
                'show_but_block' => false,
654
                'hide_node' => false,
655
                'is_pf' => in_array($nodeId, $session_personal_folder) === true ? 1 : 0,
656
            ];
657
        }
658
        
659
        return [
660
            'html' => '<span class="badge badge-pill badge-light ml-2 items_count" id="itcount_' . $nodeId . '">' . $itemsNb .
661
                ($tree_counters === 1 ? '/'.$nbChildrenItems .'/'.(count($nodeDescendants) - 1)  : '') . '</span>',
662
            'title' => $title,
663
            'restricted' => 0,
664
            'folderClass' => 'folder',
665
            'show_but_block' => false,
666
            'hide_node' => false,
667
            'is_pf' => in_array($nodeId, $session_personal_folder) === true ? 1 : 0,
668
        ];
669
670
    } elseif (in_array($nodeId, $listFoldersLimitedKeys) === true) {
671
        return [
672
            'html' => ($session_user_read_only === true ? '<i class="far fa-eye fa-xs mr-1"></i>' : '') .
673
                '<span class="badge badge-pill badge-light ml-2 items_count" id="itcount_' . $nodeId . '">' . count($session_list_folders_limited[$nodeId]) . '</span>',
674
            'title' => $title,
675
            'restricted' => 1,
676
            'folderClass' => 'folder',
677
            'show_but_block' => false,
678
            'hide_node' => false,
679
            'is_pf' => in_array($nodeId, $session_personal_folder) === true ? 1 : 0,
680
        ];
681
682
    } elseif (in_array($nodeId, $listRestrictedFoldersForItemsKeys) === true) {
683
        return [
684
            'html' => $session_user_read_only === true ? '<i class="far fa-eye fa-xs mr-1"></i>' : '' .
685
                '<span class="badge badge-pill badge-light ml-2 items_count" id="itcount_' . $nodeId . '">' . count($session_list_restricted_folders_for_items[$nodeId]) . '</span>',
686
            'title' => $title,
687
            'restricted' => 1,
688
            'folderClass' => 'folder',
689
            'show_but_block' => false,
690
            'hide_node' => false,
691
            'is_pf' => in_array($nodeId, $session_personal_folder) === true ? 1 : 0,
692
        ];
693
694
    } elseif ((int) $show_only_accessible_folders === 1
695
        && (int) $nbChildrenItems === 0
696
    ) {
697
        // folder should not be visible
698
        // only if it has no descendants
699
        if (
700
            count(
701
                array_diff(
702
                    $nodeDirectDescendants,
703
                    array_merge(
704
                        $session_groupes_visibles,
705
                        array_keys($session_list_restricted_folders_for_items)
706
                    )
707
                )
708
            ) !== count($nodeDirectDescendants)
709
        ) {
710
            // show it but block it
711
            return [
712
                'html' => '',
713
                'title' => $title,
714
                'restricted' => 1,
715
                'folderClass' => 'folder_not_droppable',
716
                'show_but_block' => true,
717
                'hide_node' => false,
718
                'is_pf' => in_array($nodeId, $session_personal_folder) === true ? 1 : 0,
719
            ];
720
        }
721
        
722
        // hide it
723
        return [
724
            'html' => '',
725
            'title' => $title,
726
            'restricted' => 1,
727
            'folderClass' => 'folder_not_droppable',
728
            'show_but_block' => false,
729
            'hide_node' => true,
730
            'is_pf' => in_array($nodeId, $session_personal_folder) === true ? 1 : 0,
731
        ];
732
    }
733
734
    return [
735
        'html' => '',
736
        'title' => isset($title) === true ? $title : '',
737
        'restricted' => 1,
738
        'folderClass' => 'folder_not_droppable',
739
        'show_but_block' => true,
740
        'hide_node' => false,
741
        'is_pf' => in_array($nodeId, $session_personal_folder) === true ? 1 : 0,
742
    ];
743
}
744
745
746
/**
747
 * Permits to check if we can user a cache instead of loading from DB
748
 *
749
 * @param integer $lastTreeChange
750
 * @param integer $userTreeLastRefresh
751
 * @param array $userSessionTreeStructure
752
 * @param integer $userId
753
 * @param integer $forceRefresh
754
 * @param array $SETTINGS
755
 * @return array
756
 */
757
function loadTreeStrategy(
758
    int $lastTreeChange,
759
    int $userTreeLastRefresh,
760
    array $userSessionTreeStructure,
761
    int $userId,
762
    int $forceRefresh
763
): array
764
{
765
    // Case when refresh is EXPECTED / MANDATORY
766
    if ((int) $forceRefresh === 1) {
767
        return [
768
            'state' => true,
769
            'data' => [],
770
        ];
771
    }
772
773
    // Case when an update in the tree has been done
774
    // Refresh is then mandatory
775
    if ((int) $lastTreeChange > (int) $userTreeLastRefresh) {
776
        return [
777
            'state' => true,
778
            'data' => [],
779
        ];
780
    }
781
782
    // Does this user has the tree structure in session?
783
    // If yes then use it
784
    if (count($userSessionTreeStructure) > 0) {
785
        return [
786
            'state' => false,
787
            'data' => json_encode($userSessionTreeStructure),
788
        ];
789
    }
790
791
    // Does this user has a tree cache
792
    $userCacheTree = DB::queryfirstrow(
793
        'SELECT data
794
        FROM ' . prefixTable('cache_tree') . '
795
        WHERE user_id = %i',
796
        $userId
797
    );
798
    if (empty($userCacheTree['data']) === false && $userCacheTree['data'] !== '[]') {
799
        return [
800
            'state' => false,
801
            'data' => $userCacheTree['data'],
802
        ];
803
    }
804
805
    return [
806
        'state' => true,
807
        'data' => [],
808
    ];
809
}