Completed
Branch dev (d5d70c)
by Raffael
11:00
created

Users   A

Complexity

Total Complexity 28

Size/Duplication

Total Lines 535
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Importance

Changes 0
Metric Value
wmc 28
lcom 1
dl 0
loc 535
rs 10
c 0
b 0
f 0
cbo 7

13 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
C _getUser() 0 23 8
A getWhoami() 0 6 1
A getNodeAttributeSummary() 0 6 1
A getGroups() 0 10 2
A getQuotaUsage() 0 6 1
A get() 0 13 4
A getAvatar() 0 9 2
A head() 0 6 1
A post() 0 11 2
A patch() 0 11 2
A delete() 0 15 2
A postUndelete() 0 6 1
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * balloon
7
 *
8
 * @copyright   Copryright (c) 2012-2018 gyselroth GmbH (https://gyselroth.com)
9
 * @license     GPL-3.0 https://opensource.org/licenses/GPL-3.0
10
 */
11
12
namespace Balloon\App\Api\v2;
13
14
use Balloon\Exception\InvalidArgument as InvalidArgumentException;
15
use Balloon\Filesystem\Acl\Exception\Forbidden as ForbiddenException;
16
use Balloon\Server;
17
use Balloon\Server\AttributeDecorator;
18
use Balloon\Server\User;
19
use Balloon\Server\User\Exception;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Balloon\App\Api\v2\Exception.

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...
20
use Micro\Http\Response;
21
use MongoDB\BSON\Binary;
22
use MongoDB\BSON\ObjectId;
23
24
class Users
25
{
26
    /**
27
     * User.
28
     *
29
     * @var User
30
     */
31
    protected $user;
32
33
    /**
34
     * Server.
35
     *
36
     * @var Server
37
     */
38
    protected $server;
39
40
    /**
41
     * Decorator.
42
     *
43
     * @var AttributeDecorator
44
     */
45
    protected $decorator;
46
47
    /**
48
     * Initialize.
49
     *
50
     * @param Server $server
51
     */
52
    public function __construct(Server $server, AttributeDecorator $decorator)
53
    {
54
        $this->user = $server->getIdentity();
55
        $this->server = $server;
56
        $this->decorator = $decorator;
57
    }
58
59
    /**
60
     * @apiDefine _getUser
61
     *
62
     * @apiParam (GET Parameter) {string[]} uid Either a single uid (user id) or a uname (username) must be given (admin privilege required).
63
     * @apiParam (GET Parameter) {string[]} uname Either a single uid (user id) or a uname (username) must be given (admin privilege required).
64
     *
65
     * @apiErrorExample {json} Error-Response (No admin privileges):
66
     * HTTP/1.1 403 Forbidden
67
     * {
68
     *      "status": 403,
69
     *      "data": {
70
     *          "error": "Balloon\\Filesystem\\Acl\\Exception\\Forbidden",
71
     *          "message": "submitted parameters require to have admin privileges",
72
     *          "code": 41
73
     *      }
74
     * }
75
     *
76
     * @apiErrorExample {json} Error-Response (User not found):
77
     * HTTP/1.1 404 Not Found
78
     * {
79
     *      "status": 404,
80
     *      "data": {
81
     *          "error": "Balloon\\Server\\User\\Exception",
82
     *          "message": "requested user was not found",
83
     *          "code": 53
84
     *      }
85
     * }
86
     *
87
     * @apiErrorExample {json} Error-Response (Invalid argument):
88
     * HTTP/1.1 400 Bad Request
89
     * {
90
     *      "status": 400,
91
     *      "data": {
92
     *          "error": "Balloon\\Exception\\InvalidArgument",
93
     *          "message": "provide either uid (user id) or uname (username)",
94
     *          "Code": 0
95
     *      }
96
     * }
97
     */
98
99
    /**
100
     * @apiDefine _getUsers
101
     *
102
     * @apiParam (GET Parameter) {string[]} uid Either a single uid (user id) as string or multiple as an array or a single uname (username) as string or multiple usernames as array must be given.
103
     * @apiParam (GET Parameter) {string[]} uname Either a single uid (userid) as string or multiple as an array or a single uname (username) as string or multiple usernames as array must be given.
104
     */
105
106
    /**
107
     * Get user instance.
108
     *
109
     * @param string $id
110
     * @param string $uname
111
     * @param bool   $require_admin
112
     *
113
     * @return User
114
     */
115
    public function _getUser(?string $id = null, ?string $uname = null, bool $require_admin = false)
116
    {
117
        if (null !== $id || null !== $uname || true === $require_admin) {
118
            if ($this->user->isAdmin()) {
119
                if (null !== $id && null !== $uname) {
120
                    throw new InvalidArgumentException('provide either uid (user id) or uname (username)');
121
                }
122
123
                if (null !== $id) {
124
                    return $this->server->getUserById(new ObjectId($id));
125
                }
126
127
                return $this->server->getUserByName($uname);
128
            }
129
130
            throw new ForbiddenException(
131
                    'submitted parameters require to have admin privileges',
132
                    ForbiddenException::ADMIN_PRIV_REQUIRED
133
                );
134
        }
135
136
        return $this->user;
137
    }
138
139
    /**
140
     * @api {get} /api/v2/users/whoami Who am I?
141
     * @apiVersion 2.0.0
142
     * @apiName getWhoami
143
     * @apiUse _getUser
144
     * @apiGroup User
145
     * @apiPermission none
146
     * @apiDescription Get the username of the authenticated user
147
     * If you want to receive your own username you have to leave the parameters uid and uname empty.
148
     * Requesting this api with parameter uid or uname requires admin privileges.
149
     *
150
     * @apiExample Example usage:
151
     * curl -XGET "https://SERVER/api/v2/users/whoami?pretty"
152
     *
153
     * @apiSuccess {string} id User ID
154
     * @apiSuccess {string} name Username
155
     * @apiSuccessExample {json} Success-Response:
156
     * HTTP/1.1 200 OK
157
     * {
158
     *     "id": "544627ed3c58891f058b4611",
159
     *     "name": "peter.meier"
160
     * }
161
     *
162
     * @param string $id
0 ignored issues
show
Bug introduced by
There is no parameter named $id. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
163
     * @param string $uname
0 ignored issues
show
Bug introduced by
There is no parameter named $uname. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
164
     *
165
     * @return Response
166
     */
167
    public function getWhoami(array $attributes = []): Response
168
    {
169
        $result = $this->decorator->decorate($this->_getUser(), $attributes);
170
171
        return (new Response())->setCode(200)->setBody($result);
172
    }
173
174
    /**
175
     * @api {get} /api/v2/users/:id/node-attribute-summary Node attribute summary
176
     * @apiVersion 2.0.0
177
     * @apiName getNodeAttributeSummary
178
     * @apiUse _getUser
179
     * @apiGroup User
180
     * @apiPermission none
181
     * @apiDescription Get summary and usage of specific node attributes
182
     * If you want to receive your own node summary you have to leave the parameters uid and uname empty.
183
     * Requesting this api with parameter uid or uname requires admin privileges.
184
     *
185
     * @apiExample Example usage:
186
     * curl -XGET "https://SERVER/api/v2/users/node-attribute-summary?pretty"
187
     * curl -XGET "https://SERVER/api/v2/users/544627ed3c58891f058b4611/node-attribute-summary?pretty"
188
     * curl -XGET "https://SERVER/api/v2/users/node-attribute-summary?uname=loginuser&pretty"
189
     *
190
     * @param string $id
191
     * @param string $uname
192
     * @param string $attributes
193
     * @param int    $limit
194
     *
195
     * @return Response
196
     */
197
    public function getNodeAttributeSummary(?string $id = null, ?string $uname = null, array $attributes = [], int $limit = 25): Response
198
    {
199
        $result = $this->_getUser($id, $uname)->getNodeAttributeSummary($attributes, $limit);
200
201
        return (new Response())->setCode(200)->setBody($result);
202
    }
203
204
    /**
205
     * @api {get} /api/v2/users/:id/groups Group membership
206
     * @apiVersion 2.0.0
207
     * @apiName getGroups
208
     * @apiUse _getUser
209
     * @apiGroup User
210
     * @apiPermission none
211
     * @apiDescription Get all user groups
212
     * If you want to receive your own groups you have to leave the parameters uid and uname empty.
213
     * Requesting this api with parameter uid or uname requires admin privileges.
214
     *
215
     * @apiExample Example usage:
216
     * curl -XGET "https://SERVER/api/v2/users/groups?pretty"
217
     * curl -XGET "https://SERVER/api/v2/users/544627ed3c58891f058b4611/groups?pretty"
218
     * curl -XGET "https://SERVER/api/v2/users/groups?uname=loginuser&pretty"
219
     *
220
     * @apiSuccess {object[]} - List of groups
221
     * @apiSuccess {string} -.id Group ID
222
     * @apiSuccess {string} -.name Name
223
     * @apiSuccessExample {json} Success-Response:
224
     * HTTP/1.1 200 OK
225
     * [
226
     *  {
227
     *      "id": "544627ed3c58891f058b4611",
228
     *      "name": "group"
229
     *  }
230
     * ]
231
     *
232
     * @param string $id
233
     * @param string $uname
234
     */
235
    public function getGroups(?string $id = null, ?string $uname = null, array $attributes = []): Response
236
    {
237
        $body = [];
238
239
        foreach ($this->_getUser($id, $uname)->getGroups() as $group) {
240
            $body[] = $this->decorator->decorate($group, $attributes);
241
        }
242
243
        return (new Response())->setCode(200)->setBody($body);
244
    }
245
246
    /**
247
     * @api {get} /api/v2/users/:id/quota-usage Quota usage
248
     * @apiVersion 2.0.0
249
     * @apiName getQuotaUsage
250
     * @apiUse _getUser
251
     * @apiGroup User
252
     * @apiPermission none
253
     * @apiDescription Get user quota usage (including hard,soft,used and available space).
254
     * If you want to receive your own quota you have to leave the parameters uid and uname empty.
255
     * Requesting this api with parameter uid or uname requires admin privileges.
256
     *
257
     * @apiExample Example usage:
258
     * curl -XGET "https://SERVER/api/v2/users/quota-usage?pretty"
259
     * curl -XGET "https://SERVER/api/v2/users/544627ed3c58891f058b4611/quota-usage?pretty"
260
     * curl -XGET "https://SERVER/api/v2/users/quota-usage?uname=loginuser&pretty"
261
     *
262
     * @apiSuccess {number} used Used quota in bytes
263
     * @apiSuccess {number} available Quota left in bytes
264
     * @apiSuccess {number} hard_quota Hard quota in bytes
265
     * @apiSuccess {number} soft_quota Soft quota (Warning) in bytes
266
     * @apiSuccessExample {json} Success-Response:
267
     * HTTP/1.1 200 OK
268
     * {
269
     *      "used": 15543092,
270
     *      "available": 5353166028,
271
     *      "hard_quota": 5368709120,
272
     *      "soft_quota": 5368709120
273
     * }
274
     *
275
     * @param string $id
276
     * @param string $uname
277
     *
278
     * @return Response
279
     */
280
    public function getQuotaUsage(?string $id = null, ?string $uname = null): Response
281
    {
282
        $result = $this->_getUser($id, $uname)->getQuotaUsage();
283
284
        return (new Response())->setCode(200)->setBody($result);
285
    }
286
287
    /**
288
     * @api {get} /api/v2/users/:id User attributes
289
     * @apiVersion 2.0.0
290
     * @apiName get
291
     * @apiUse _getUser
292
     * @apiGroup User
293
     * @apiPermission none
294
     * @apiDescription Get all user attributes including username, mail, id,....
295
     * If you want to receive your own attributes you have to leave the parameters uid and uname empty.
296
     * Requesting this api with parameter uid or uname requires admin privileges.
297
     *
298
     * @apiExample Example usage:
299
     * curl -XGET "https://SERVER/api/v2/users/attributes?pretty"
300
     * curl -XGET "https://SERVER/api/v2/users/544627ed3c58891f058b4611/attributes?pretty"
301
     * curl -XGET "https://SERVER/api/v2/users/attributes?uname=loginser&pretty"
302
     *
303
     * @apiSuccess (200 OK) {string} id User ID
304
     *
305
     * @apiSuccessExample {json} Success-Response:
306
     * HTTP/1.1 200 OK
307
     * {
308
     *      "id": "544627ed3c58891f058b4611",
309
     *      "name": "loginuser"
310
     * }
311
     *
312
     * @param string $id
313
     * @param string $uname
314
     * @param string $attributes
315
     *
316
     * @return Response
317
     */
318
    public function get(?string $id = null, ?string $uname = null, array $filter = [], array $attributes = []): Response
319
    {
320
        if ($id === null && $uname === null) {
321
            $result = [];
322
            foreach ($this->server->getUsers($filter) as $user) {
323
                $result[] = $this->decorator->decorate($user, $attributes);
324
            }
325
        } else {
326
            $result = $this->decorator->decorate($this->_getUser($id, $uname), $attributes);
327
        }
328
329
        return (new Response())->setCode(200)->setBody($result);
330
    }
331
332
    /**
333
     * @api {get} /api/v2/users/:id/avatar Get user avatar
334
     * @apiVersion 2.0.0
335
     * @apiName getAvatar
336
     * @apiUse _getUser
337
     * @apiGroup User
338
     * @apiPermission none
339
     * @apiDescription Get users avaatr
340
     *
341
     * @apiExample Example usage:
342
     * curl -XGET "https://SERVER/api/v2/users/avatar?pretty"
343
     * curl -XGET "https://SERVER/api/v2/users/544627ed3c58891f058b4611/avatar?pretty"
344
     * curl -XGET "https://SERVER/api/v2/users/avatar?uname=loginser&pretty"
345
     *
346
     * @apiSuccess (200 OK) {string} id User ID
347
     *
348
     * @apiSuccessExample {json} Success-Response:
349
     * HTTP/1.1 200 OK
350
     *
351
     * @param string $id
352
     * @param string $uname
353
     *
354
     * @return Response
355
     */
356
    public function getAvatar(?string $id = null, ?string $uname = null): Response
357
    {
358
        $avatar = $this->_getUser($id, $uname)->getAttributes()['avatar'];
359
        if ($avatar instanceof Binary) {
0 ignored issues
show
Bug introduced by
The class MongoDB\BSON\Binary does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
360
            return (new Response())->setCode(200)->setBody(base64_encode($avatar->getData()));
361
        }
362
363
        return (new Response())->setCode(404);
364
    }
365
366
    /**
367
     * @api {head} /api/v2/users/:id User exists?
368
     * @apiVersion 2.0.0
369
     * @apiName head
370
     * @apiUse _getUser
371
     * @apiGroup User
372
     * @apiPermission admin
373
     * @apiDescription Check if user account exists
374
     *
375
     * @apiExample Example usage:
376
     * curl -XHEAD "https://SERVER/api/v2/user"
377
     * curl -XHEAD "https://SERVER/api/v2/users/544627ed3c58891f058b4611"
378
     * curl -XHEAD "https://SERVER/api/v2/user?uname=loginuser"
379
     *
380
     * @apiSuccessExample {json} Success-Response:
381
     * HTTP/1.1 204 No Content
382
     *
383
     * @param string $uname
384
     * @param string $id
385
     *
386
     * @return Response
387
     */
388
    public function head(?string $id = null, ?string $uname = null): Response
389
    {
390
        $result = $this->_getUser($id, $uname, true);
0 ignored issues
show
Unused Code introduced by
$result is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
391
392
        return (new Response())->setCode(204);
393
    }
394
395
    /**
396
     * @api {post} /api/v2/users Create user
397
     * @apiVersion 2.0.0
398
     * @apiName post
399
     * @apiGroup User
400
     * @apiPermission admin
401
     * @apiDescription Create user
402
     *
403
     * @apiExample Example usage:
404
     * curl -XPOST "https://SERVER/api/v2/user"
405
     *
406
     * @apiParam (POST Parameter) {string} username Name of the new user
407
     * @apiParam (POST Parameter) {string} [attributes.password] Password
408
     * @apiParam (POST Parameter) {string} [attributes.mail] Mail address
409
     * @apiParam (POST Parameter) {string} [attributes.avatar] Avatar image base64 encoded
410
     * @apiParam (POST Parameter) {string} [attributes.namespace] User namespace
411
     * @apiParam (POST Parameter) {number} [attributes.hard_quota] The new hard quota in bytes (Unlimited by default)
412
     * @apiParam (POST Parameter) {number} [attributes.soft_quota] The new soft quota in bytes (Unlimited by default)
413
     *
414
     * @apiSuccess (200 OK) {string} id User ID
415
     *
416
     * @apiSuccessExample {json} Success-Response:
417
     * HTTP/1.1 201 Created
418
     * {
419
     *      "id": "544627ed3c58891f058b4633"
420
     * }
421
     *
422
     * @param string $username
423
     * @param array  $attributes
424
     *
425
     * @return Response
426
     */
427
    public function post(string $username, array $attributes = []): Response
428
    {
429
        if (isset($attributes['avatar'])) {
430
            $attributes['avatar'] = new Binary(base64_decode($attributes['avatar']), Binary::TYPE_GENERIC);
431
        }
432
433
        $id = $this->server->addUser($username, $attributes);
434
        $result = $this->decorator->decorate($this->server->getUserById($id));
435
436
        return (new Response())->setBody($result)->setCode(201);
437
    }
438
439
    /**
440
     * @api {patch} /api/v2/users/:id Change attributes
441
     * @apiVersion 2.0.0
442
     * @apiName patch
443
     * @apiUse _getUser
444
     * @apiGroup User
445
     * @apiPermission admin
446
     * @apiDescription Set attributes for user
447
     *
448
     * @apiExample Example usage:
449
     * curl -XPOST "https://SERVER/api/v2/users/attributes" -d '{"attributes": ["mail": "[email protected]"]}'
450
     * curl -XPOST "https://SERVER/api/v2/users/attributes?{%22attributes%22:[%22mail%22:%[email protected]%22]}""
451
     * curl -XPOST "https://SERVER/api/v2/users/544627ed3c58891f058b4611/attributes" -d '{"attributes": ["admin": "false"]}'
452
     * curl -XPOST "https://SERVER/api/v2/users/quota?uname=loginuser"  -d '{"attributes": ["admin": "false"]}'
453
     *
454
     * @apiParam (POST Parameter) {[]} attributes
455
     * @apiParam (POST Parameter) {number} attributes.hard_quota The new hard quota in bytes
456
     * @apiParam (POST Parameter) {number} attributes.soft_quota The new soft quota in bytes
457
     *
458
     * @apiSuccessExample {json} Success-Response:
459
     * HTTP/1.1 200 OK
460
     *
461
     * @param string $uname
462
     * @param string $id
463
     * @param array  $attributes
464
     *
465
     * @return Response
466
     */
467
    public function patch(array $attributes = [], ?string $id = null, ?string $uname = null): Response
468
    {
469
        if (isset($attributes['avatar'])) {
470
            $attributes['avatar'] = new Binary(base64_decode($attributes['avatar']), Binary::TYPE_GENERIC);
471
        }
472
473
        $user = $this->_getUser($id, $uname, true)->setAttributes($attributes);
474
        $result = $this->decorator->decorate($user);
0 ignored issues
show
Documentation introduced by
$user is of type boolean, but the function expects a object<Balloon\Server\RoleInterface>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
475
476
        return (new Response())->setCode(200)->setBody($result);
477
    }
478
479
    /**
480
     * @api {delete} /api/v2/users/:id Delete user
481
     * @apiVersion 2.0.0
482
     * @apiName delete
483
     * @apiUse _getUser
484
     * @apiGroup User
485
     * @apiPermission admin
486
     * @apiDescription Delete user account, this will also remove any data owned by the user. If force is false, all data gets moved to the trash. If force
487
     * is true all data owned by the user gets ereased.
488
     *
489
     * @apiExample Example usage:
490
     * curl -XDELETE "https://SERVER/api/v2/users/544627ed3c58891f058b4611?force=1"
491
     * curl -XDELETE "https://SERVER/api/v2/user?uname=loginuser"
492
     *
493
     * @apiParam (GET Parameter) {bool} [force=false] Per default the user account will be disabled, if force is set
494
     * the user account gets removed completely.
495
     *
496
     * @apiErrorExample {json} Error-Response (Can not delete yourself):
497
     * HTTP/1.1 400 Bad Request
498
     * {
499
     *      "status": 400,
500
     *      "data": {
501
     *          "error": "Balloon\\Server\\User\\Exception",
502
     *          "message": "requested user was not found"
503
     *      }
504
     * }
505
     *
506
     * @apiSuccessExample {json} Success-Response:
507
     * HTTP/1.1 204 No Content
508
     *
509
     * @param string $uname
510
     * @param string $id
511
     * @param bool   $force
512
     *
513
     * @return Response
514
     */
515
    public function delete(?string $id = null, ?string $uname = null, bool $force = false): Response
516
    {
517
        $user = $this->_getUser($id, $uname, true);
518
519
        if ($user->getId() === $this->user->getId()) {
520
            throw new Exception(
521
                'can not delete yourself',
522
                Exception::CAN_NOT_DELETE_OWN_ACCOUNT
523
            );
524
        }
525
526
        $user->delete($force);
527
528
        return (new Response())->setCode(204);
529
    }
530
531
    /**
532
     * @api {post} /api/v2/users/:id/undelete Enable user account
533
     * @apiVersion 2.0.0
534
     * @apiName postUndelete
535
     * @apiUse _getUser
536
     * @apiGroup User
537
     * @apiPermission admin
538
     * @apiDescription Apiore user account. This endpoint does not restore any data, it only does reactivate an existing user account.
539
     *
540
     * @apiExample Example usage:
541
     * curl -XPOST "https://SERVER/api/v2/users/544627ed3c58891f058b4611/undelete"
542
     * curl -XPOST "https://SERVER/api/v2/users/undelete?user=loginuser"
543
     *
544
     * @apiSuccessExample {json} Success-Response:
545
     * HTTP/1.1 204 No Content
546
     *
547
     * @param string $uname
548
     * @param string $id
549
     *
550
     * @return Response
551
     */
552
    public function postUndelete(?string $id = null, ?string $uname = null): Response
553
    {
554
        $this->_getUser($id, $uname, true)->undelete();
555
556
        return (new Response())->setCode(204);
557
    }
558
}
559