Passed
Push — master ( fd5210...56a3aa )
by Nils
04:41
created

createNewFolder()   F

Complexity

Conditions 51
Paths 8660

Size

Total Lines 314
Code Lines 186

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 51
eloc 186
c 1
b 0
f 0
nc 8660
nop 16
dl 0
loc 314
rs 0

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 file is part of the TeamPass project.
9
 * 
10
 * TeamPass is free software: you can redistribute it and/or modify it
11
 * under the terms of the GNU General Public License as published by
12
 * the Free Software Foundation, version 3 of the License.
13
 * 
14
 * TeamPass is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
 * GNU General Public License for more details.
18
 * 
19
 * You should have received a copy of the GNU General Public License
20
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21
 * 
22
 * Certain components of this file may be under different licenses. For
23
 * details, see the `licenses` directory or individual file headers.
24
 * ---
25
 * @file      folders.functions.php
26
 * @author    Nils Laumaillé ([email protected])
27
 * @copyright 2009-2024 Teampass.net
28
 * @license   GPL-3.0
29
 * @see       https://www.teampass.net
30
 */
31
32
use TeampassClasses\NestedTree\NestedTree;
33
use TeampassClasses\SessionManager\SessionManager;
34
use Symfony\Component\HttpFoundation\Request;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Request. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
35
use TeampassClasses\Language\Language;
36
37
// Load functions
38
require_once 'main.functions.php';
39
40
// init
41
loadClasses('DB');
42
$request = Request::createFromGlobals();
43
44
45
function createNewFolder(
46
    string $title,
47
    int $parent_id,
48
    int $complexity,
49
    int $duration,
50
    int $create_auth_without,
51
    int $edit_auth_without,
52
    string $icon,
53
    string $icon_selected,
54
    string $access_rights,
55
    int $user_is_admin,
56
    array $user_accessible_folders,
57
    int $user_is_manager,
58
    int $user_can_create_root_folder,
59
    int $user_can_manage_all_users,
60
    int $user_id,
61
    string $user_roles
62
): array
63
{
64
    $session = SessionManager::getSession();
65
    $lang = new Language();
66
67
    // Load config if $SETTINGS not defined
68
    try {
69
        include_once __DIR__.'/../includes/config/tp.config.php';
70
    } catch (Exception $e) {
71
        throw new Exception("Error file '/includes/config/tp.config.php' not exists", 1);
72
    }
73
74
    // Init
75
    $error = false;
0 ignored issues
show
Unused Code introduced by
The assignment to $error is dead and can be removed.
Loading history...
76
    $newId = '';
77
78
    // check if title is numeric
79
    if (is_numeric($title) === true) {
80
        return array(
81
            'error' => true,
82
            'message' => $lang->get('error_only_numbers_in_folder_name'),
83
            'newId' => $newId,
84
        );
85
    }
86
    // Check if parent folder is allowed for this user
87
    if (
88
        in_array($parent_id, $user_accessible_folders) === false
89
        && (int) $user_is_admin !== 1
90
    ) {
91
        return array(
92
            'error' => true,
93
            'message' => $lang->get('error_not_allowed_to'),
94
            'newId' => $newId."1",
95
        );
96
    }
97
98
    //Check if duplicate folders name are allowed
99
    if (
100
        isset($SETTINGS['duplicate_folder']) === true
1 ignored issue
show
Comprehensibility Best Practice introduced by
The variable $SETTINGS seems to never exist and therefore isset should always be false.
Loading history...
101
        && (int) $SETTINGS['duplicate_folder'] === 0
102
    ) {
103
        DB::query(
104
            'SELECT *
105
            FROM ' . prefixTable('nested_tree') . '
106
            WHERE title = %s',
107
            $title
108
        );
109
        $counter = DB::count();
110
        if ($counter !== 0) {
111
            return array(
112
                'error' => true,
113
                'message' => $lang->get('error_group_exist'),
114
                'newId' => $newId,
115
            );
116
        }
117
    }
118
119
    //check if parent folder is personal
120
    $data = DB::queryfirstrow(
121
        'SELECT personal_folder, bloquer_creation, bloquer_modification
122
        FROM ' . prefixTable('nested_tree') . '
123
        WHERE id = %i',
124
        $parent_id
125
    );
126
127
    // inherit from parent the specific settings it has
128
    if (DB::count() > 0) {
129
        $parentBloquerCreation = $data['bloquer_creation'];
130
        $parentBloquerModification = $data['bloquer_modification'];
131
    } else {
132
        $parentBloquerCreation = 0;
133
        $parentBloquerModification = 0;
134
    }
135
136
    if (isset($data) === true && (int) $data['personal_folder'] === 1) {
137
        $isPersonal = 1;
138
    } else {
139
        $isPersonal = 0;
140
141
        // check if complexity level is good
142
        // if manager or admin don't care
143
        if (
144
            $user_is_admin === 0
145
            && ((int) $user_is_manager !== 1
146
                || (int) $user_can_manage_all_users !== 1)
147
        ) {
148
            // get complexity level for this folder
149
            $data = DB::queryfirstrow(
150
                'SELECT valeur
151
                FROM ' . prefixTable('misc') . '
152
                WHERE intitule = %i AND type = %s',
153
                $parent_id,
154
                'complex'
155
            );
156
            if (isset($data['valeur']) === true && intval($complexity) < intval($data['valeur'])) {
157
                return array(
158
                    'error' => true,
159
                    'message' => $lang->get('error_folder_complexity_lower_than_top_folder')
160
                        . ' [<b>' . TP_PW_COMPLEXITY[$data['valeur']][1] . '</b>]',
161
                    'newId' => $newId,
162
                );
163
            }
164
        }
165
    }
166
167
    if (
168
        (int) $isPersonal === 1
169
        || (int) $user_is_admin === 1
170
        || ((int) $user_is_manager === 1 || (int) $user_can_manage_all_users === 1)
171
        || (isset($SETTINGS['enable_user_can_create_folders']) === true
172
            && (int) $SETTINGS['enable_user_can_create_folders'] == 1)
173
        || ((int) $user_can_create_root_folder && null !== $user_can_create_root_folder && (int) $user_can_create_root_folder === 1)
174
    ) {
175
        //create folder
176
        DB::insert(
177
            prefixTable('nested_tree'),
178
            array(
179
                'parent_id' => $parent_id,
180
                'title' => $title,
181
                'personal_folder' => $isPersonal,
182
                'renewal_period' => isset($duration) === true && (int) $duration !== 0 ? $duration : 0,
183
                'bloquer_creation' => isset($create_auth_without) === true && (int) $create_auth_without === 1 ? '1' : $parentBloquerCreation,
184
                'bloquer_modification' => isset($edit_auth_without) === true && (int) $edit_auth_without === 1 ? '1' : $parentBloquerModification,
185
                'fa_icon' => empty($icon) === true ? TP_DEFAULT_ICON : $icon,
186
                'fa_icon_selected' => empty($icon_selected) === true ? TP_DEFAULT_ICON_SELECTED : $icon_selected,
187
                'categories' => '',
188
            )
189
        );
190
        $newId = DB::insertId();
191
192
        //Add complexity
193
        DB::insert(
194
            prefixTable('misc'),
195
            array(
196
                'type' => 'complex',
197
                'intitule' => $newId,
198
                'valeur' => $complexity,
199
            )
200
        );
201
202
        // ensure categories are set
203
        handleFoldersCategories(
204
            [$newId]
205
        );
206
207
        // Update timestamp
208
        DB::update(
209
            prefixTable('misc'),
210
            array(
211
                'valeur' => time(),
212
            ),
213
            'type = %s AND intitule = %s',
214
            'timestamp',
215
            'last_folder_change'
216
        );
217
218
        // add new folder id in SESSION
219
        if ($session->has('user-accessible_folders') === true) {
220
            $session->set('user-accessible_folders', array_unique(array_merge($session->get('user-accessible_folders'), [$newId]), SORT_NUMERIC));
221
            if ((int) $isPersonal === 1) {
222
                SessionManager::addRemoveFromSessionArray('user-personal_folders', [$newId], 'add');
223
            }
224
        }
225
226
        // Load tree
227
        $tree = new NestedTree(prefixTable('nested_tree'), 'id', 'parent_id', 'title');
228
229
        // rebuild tree
230
        $tree->rebuild();
231
232
233
        // --> build json tree if not Admin
234
        if ($user_is_admin === 0) {
235
            // Get path
236
            $path = '';
237
            $tree_path = $tree->getPath(0, false);
238
            foreach ($tree_path as $fld) {
239
                $path .= empty($path) === true ? $fld->title : '/'.$fld->title;
240
            }
241
            $new_json = [
242
                "path" => $path,
243
                "id" => $newId,
244
                "level" => count($tree_path),
245
                "title" => $title,
246
                "disabled" => 0,
247
                "parent_id" => $parent_id,
248
                "perso" => $isPersonal,
249
                "is_visible_active" => 0,
250
            ];
251
252
            // update cache_tree
253
            $cache_tree = DB::queryfirstrow(
254
                'SELECT increment_id, folders, visible_folders
255
                FROM ' . prefixTable('cache_tree').' WHERE user_id = %i',
256
                (int) $user_id
257
            );
258
            if (empty($cache_tree) === true) {
259
                DB::insert(
260
                    prefixTable('cache_tree'),
261
                    array(
262
                        'user_id' => $user_id,
263
                        'folders' => json_encode($newId),
264
                        'visible_folders' => json_encode($new_json),
265
                        'timestamp' => time(),
266
                        'data' => '[{}]',
267
                    )
268
                );
269
            } else {
270
                $a_folders = is_null($cache_tree['folders']) === true ? [] : json_decode($cache_tree['folders'], true);
271
                array_push($a_folders, $newId);
272
                $a_visible_folders = is_null($cache_tree['visible_folders']) === true || empty($cache_tree['visible_folders']) === true ? [] : json_decode($cache_tree['visible_folders'], true);
273
                array_push($a_visible_folders, $new_json);
274
                DB::update(
275
                    prefixTable('cache_tree'),
276
                    array(
277
                        'folders' => json_encode($a_folders),
278
                        'visible_folders' => json_encode($a_visible_folders),
279
                        'timestamp' => time(),
280
                    ),
281
                    'increment_id = %i',
282
                    (int) $cache_tree['increment_id']
283
                );
284
            }
285
        }
286
        // <-- end - build json tree
287
288
        // Create expected groups access rights based upon option selected
289
        if (
290
            isset($SETTINGS['subfolder_rights_as_parent']) === true
291
            && (int) $SETTINGS['subfolder_rights_as_parent'] === 1
292
        ) {
293
            //If it is a subfolder, then give access to it for all roles that allows the parent folder
294
            $rows = DB::query('SELECT role_id, type FROM ' . prefixTable('roles_values') . ' WHERE folder_id = %i', $parent_id);
295
            foreach ($rows as $record) {
296
                //add access to this subfolder
297
                DB::insert(
298
                    prefixTable('roles_values'),
299
                    array(
300
                        'role_id' => $record['role_id'],
301
                        'folder_id' => $newId,
302
                        'type' => $record['type'],
303
                    )
304
                );
305
            }
306
        } elseif ((int) $user_is_admin !== 1) {
307
            // If not admin and no option enabled
308
            // then provide expected rights based upon user's roles
309
            foreach (explode(';', $user_roles) as $role) {
310
                if (empty($role) === false) {
311
                    DB::insert(
312
                        prefixTable('roles_values'),
313
                        array(
314
                            'role_id' => $role,
315
                            'folder_id' => $newId,
316
                            'type' => $access_rights,
317
                        )
318
                    );
319
                }
320
            }
321
        }
322
323
        // if parent folder has Custom Fields Categories then add to this child one too
324
        $rows = DB::query('SELECT id_category FROM ' . prefixTable('categories_folders') . ' WHERE id_folder = %i', $parent_id);
325
        foreach ($rows as $record) {
326
            //add CF Category to this subfolder
327
            DB::insert(
328
                prefixTable('categories_folders'),
329
                array(
330
                    'id_category' => $record['id_category'],
331
                    'id_folder' => $newId,
332
                )
333
            );
334
        }
335
336
        // clear cache cache for each user that have at least one similar role as the current user
337
        $usersWithSimilarRoles = empty($user_roles) === false  ? getUsersWithRoles(
338
            explode(";", $user_roles)
339
        ) : [];
340
        foreach ($usersWithSimilarRoles as $user) {
341
            // delete cache tree
342
            DB::delete(
343
                prefixTable('cache_tree'),
344
                'user_id = %i',
345
                $user
346
            );
347
        }
348
        return array(
349
            'error' => false,
350
            'message' => '',
351
            'newId' => $newId,
352
        );
353
354
    } else {
355
        return array(
356
            'error' => true,
357
            'message' => $lang->get('error_not_allowed_to'),
358
            'newId' => $newId."2",
359
        );
360
    }
361
}