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

loadTreeStrategy()   B

Complexity

Conditions 6
Paths 5

Size

Total Lines 51
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 6
eloc 23
c 2
b 0
f 0
nc 5
nop 5
dl 0
loc 51
rs 8.9297

How to fix   Long Method   

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:

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
}