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

Groups::patch()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 7
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 4
nc 1
nop 3
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;
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...
15
use Balloon\Filesystem\Acl\Exception\Forbidden as ForbiddenException;
16
use Balloon\Server;
17
use Balloon\Server\AttributeDecorator;
18
use Balloon\Server\Group;
19
use Balloon\Server\User;
20
use Micro\Http\Response;
21
use MongoDB\BSON\ObjectId;
22
23
class Groups
24
{
25
    /**
26
     * User.
27
     *
28
     * @var User
29
     */
30
    protected $user;
31
32
    /**
33
     * Server.
34
     *
35
     * @var Server
36
     */
37
    protected $server;
38
39
    /**
40
     * Attribute decorator.
41
     *
42
     * @var AttributeDecorator
43
     */
44
    protected $decorator;
45
46
    /**
47
     * Initialize.
48
     *
49
     * @param Server $server
50
     * @param AttributeDecorator
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 _getGroup
61
     *
62
     * @apiParam (GET Parameter) {string[]} id Either a single id (group id) or a name (groupname) must be given (admin privilege required).
63
     * @apiParam (GET Parameter) {string[]} name Either a single id (group id) or a name (groupname) 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\\Exception\\Forbidden",
71
     *          "message": "submitted parameters require to have admin privileges",
72
     *          "code": 41
73
     *      }
74
     * }
75
     *
76
     * @apiErrorExample {json} Error-Response (Group not found):
77
     * HTTP/1.1 404 Not Found
78
     * {
79
     *      "status": 404,
80
     *      "data": {
81
     *          "error": "Balloon\\Exception\\NotFound",
82
     *          "message": "requested group 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 id (group id) or name (groupname)",
94
     *          "Code": 0
95
     *      }
96
     * }
97
     */
98
99
    /**
100
     * @apiDefine _getGroups
101
     *
102
     * @apiParam (GET Parameter) {string[]} id Either a single id (group id) as string or multiple as an array or a single name (groupname) as string or multiple groupnames as array must be given.
103
     * @apiParam (GET Parameter) {string[]} name Either a single id (groupid) as string or multiple as an array or a single name (groupname) as string or multiple groupnames as array must be given.
104
     */
105
106
    /**
107
     * Get group instance.
108
     *
109
     * @param string $id
110
     * @param string $name
111
     * @param bool   $require_admin
112
     *
113
     * @return Group
114
     */
115
    public function _getGroup(?string $id = null, ?string $name = null, bool $require_admin = false): Group
116
    {
117
        if (null !== $id || null !== $name || true === $require_admin) {
118
            if ($this->user->isAdmin()) {
119
                if (null !== $id && null !== $name) {
120
                    throw new Exception\InvalidArgument('provide either id (group id) or name (groupname)');
121
                }
122
123
                if (null !== $id) {
124
                    return $this->server->getGroupById(new ObjectId($id));
125
                }
126
127
                return $this->server->getGroupByName($name);
128
            }
129
130
            throw new ForbiddenException(
131
                    'submitted parameters require to have admin privileges',
132
                    ForbiddenException::ADMIN_PRIV_REQUIRED
133
                );
134
        }
135
    }
136
137
    /**
138
     * @api {get} /api/v2/groups/:id/member Get group member
139
     * @apiVersion 2.0.0
140
     * @apiName getMember
141
     * @apiUse _getGroup
142
     * @apiGroup Group
143
     * @apiPermission none
144
     * @apiDescription Request all member of a group
145
     *
146
     * @apiExample Example usage:
147
     * curl -XGET "https://SERVER/api/v2/groups/member?pretty"
148
     * curl -XGET "https://SERVER/api/v2/groups/544627ed3c58891f058b4611/member?pretty"
149
     * curl -XGET "https://SERVER/api/v2/groups/member?name=logingroup&pretty"
150
     *
151
     * @apiSuccess {object[]} - List of user
152
     * @apiSuccess {string} -.id User ID
153
     * @apiSuccess {string} -.name Username
154
     * @apiSuccess {string} -.mail Mail address
155
     * @apiSuccessExample {json} Success-Response:
156
     * HTTP/1.1 200 OK
157
     * [
158
     *  {
159
     *      "id": "544627ed3c58891f058b4613",
160
     *      "name": "ted",
161
     *      "mail": "[email protected]"
162
     *  }
163
     * ]
164
     *
165
     * @param string $id
166
     * @param string $name
167
     * @param array  $attributes
168
     */
169
    public function getMember(?string $id = null, ?string $name = null, array $attributes = []): Response
170
    {
171
        $result = $this->_getGroup($id, $name)->getResolvedMember();
172
        $body = [];
173
174
        foreach ($result as $member) {
175
            $body[] = $this->decorator->decorate($member, $attributes);
176
        }
177
178
        return (new Response())->setCode(200)->setBody($body);
179
    }
180
181
    /**
182
     * @api {get} /api/v2/groups/:id Get group attributes
183
     * @apiVersion 2.0.0
184
     * @apiName get
185
     * @apiUse _getGroup
186
     * @apiGroup Group
187
     * @apiPermission none
188
     * @apiDescription Get group attributes
189
     *
190
     * @apiExample Example usage:
191
     * curl -XGET "https://SERVER/api/v2/groups/attributes?pretty"
192
     * curl -XGET "https://SERVER/api/v2/groups/544627ed3c58891f058b4611/attributes?pretty"
193
     * curl -XGET "https://SERVER/api/v2/groups/attributes?name=loginser&pretty"
194
     *
195
     * @apiSuccess (200 OK) {string} id group ID
196
     * @apiSuccess (200 OK) {string} name group name
197
     *
198
     * @apiSuccessExample {json} Success-Response:
199
     * HTTP/1.1 200 OK
200
     * {
201
     *      "id": "544627ed3c58891f058b46cd",
202
     *      "name": "test"
203
     * }
204
     *
205
     * @param string $id
206
     * @param string $name
207
     * @param string $attributes
208
     *
209
     * @return Response
210
     */
211
    public function get(?string $id = null, ?string $name = null, array $filter = [], array $attributes = []): Response
212
    {
213
        if ($id === null && $name === null) {
214
            $result = [];
215
            foreach ($this->server->getGroups($filter) as $group) {
216
                $result[] = $this->decorator->decorate($group, $attributes);
217
            }
218
        } else {
219
            $result = $this->decorator->decorate($this->_getGroup($id, $name), $attributes);
220
        }
221
222
        return (new Response())->setCode(200)->setBody($result);
223
    }
224
225
    /**
226
     * @api {head} /api/v2/groups/:id Group exists
227
     * @apiVersion 2.0.0
228
     * @apiName postQuota
229
     * @apiUse _getGroup
230
     * @apiGroup Group
231
     * @apiPermission admin
232
     * @apiDescription Check if group account exists
233
     *
234
     * @apiExample Example usage:
235
     * curl -XHEAD "https://SERVER/api/v2/group"
236
     * curl -XHEAD "https://SERVER/api/v2/groups/544627ed3c58891f058b4611"
237
     * curl -XHEAD "https://SERVER/api/v2/group?name=logingroup"
238
     *
239
     * @apiSuccessExample {json} Success-Response:
240
     * HTTP/1.1 204 No Content
241
     *
242
     * @param string $name
243
     * @param string $id
244
     *
245
     * @return Response
246
     */
247
    public function head(?string $id = null, ?string $name = null): Response
248
    {
249
        $result = $this->_getGroup($id, $name, 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...
250
251
        return (new Response())->setCode(204);
252
    }
253
254
    /**
255
     * @api {post} /api/v2/group Create group
256
     * @apiVersion 2.0.0
257
     * @apiName postGroup
258
     * @apiGroup Group
259
     * @apiPermission admin
260
     * @apiDescription Create group
261
     *
262
     * @apiExample Example usage:
263
     * curl -XPOST "https://SERVER/api/v2/group"
264
     *
265
     * @apiParam (POST Parameter) {string} name of the new group
266
     * @apiParam (POST Parameter) {string[]} ID of group member
267
     * @apiParam (POST Parameter) {string[]} Attributes
268
     *
269
     * @apiSuccess (200 OK) {string} id group ID
270
     * @apiSuccess (200 OK) {string} name group name
271
     *
272
     * @apiSuccessExample {json} Success-Response:
273
     * HTTP/1.1 201 Created
274
     * {
275
     *      "id": "544627ed3c58891f058b46cd",
276
     *      "name": "test"
277
     * }
278
     *
279
     * @param string $name
280
     * @param array  $member
281
     * @param array  $attributes
282
     *
283
     * @return Response
284
     */
285
    public function post(string $name, array $member, array $attributes = []): Response
286
    {
287
        $id = $this->server->addGroup($name, $member, $attributes);
288
        $result = $this->decorator->decorate($this->server->getGroupById($id));
289
290
        return (new Response())->setBody($result)->setCode(201);
291
    }
292
293
    /**
294
     * @api {patch} /api/v2/groups/:id Change group attributes
295
     * @apiVersion 2.0.0
296
     * @apiName patch
297
     * @apiUse _getGroup
298
     * @apiGroup Group
299
     * @apiPermission admin
300
     * @apiDescription Set attributes for group
301
     *
302
     * @apiExample Example usage:
303
     * curl -XPOST "https://SERVER/api/v2/groups/attributes" -d '{"attributes": ["mail": "[email protected]"]}'
304
     * curl -XPOST "https://SERVER/api/v2/groups/attributes?{%22attributes%22:[%22mail%22:%[email protected]%22]}""
305
     * curl -XPOST "https://SERVER/api/v2/groups/544627ed3c58891f058b4611/attributes" -d '{"attributes": ["admin": "false"]}'
306
     * curl -XPOST "https://SERVER/api/v2/groups/quota?name=logingroup"  -d '{"attributes": ["admin": "false"]}'
307
     *
308
     * @apiSuccessExample {json} Success-Response:
309
     * HTTP/1.1 200 OK
310
     *
311
     * @param string $name
312
     * @param string $id
313
     * @param array  $attributes
314
     *
315
     * @return Response
316
     */
317
    public function patch(array $attributes = [], ?string $id = null, ?string $name = null): Response
318
    {
319
        $group = $this->_getGroup($id, $name, true)->setAttributes($attributes);
320
        $result = $this->decorator->decorate($group);
0 ignored issues
show
Documentation introduced by
$group 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...
321
322
        return (new Response())->setCode(200)->setBody($result);
323
    }
324
325
    /**
326
     * @api {delete} /api/v2/groups/:id Delete group
327
     * @apiVersion 2.0.0
328
     * @apiName delete
329
     * @apiUse _getGroup
330
     * @apiGroup Group
331
     * @apiPermission admin
332
     * @apiDescription Delete group
333
     *
334
     * @apiExample Example usage:
335
     * curl -XDELETE "https://SERVER/api/v2/groups/544627ed3c58891f058b4611?force=1"
336
     * curl -XDELETE "https://SERVER/api/v2/group?name=logingroup"
337
     *
338
     * @apiParam (GET Parameter) {bool} [force=false] Per default the group gets disabled, if force is set
339
     * the group gets removed completely.
340
     *
341
     * @apiErrorExample {json} Error-Response (Can not delete yourself):
342
     * HTTP/1.1 400 Bad Request
343
     * {
344
     *      "status": 400,
345
     *      "data": {
346
     *          "error": "Balloon\\Exception\\Conflict",
347
     *          "message": "requested group was not found"
348
     *      }
349
     * }
350
     *
351
     * @apiSuccessExample {json} Success-Response:
352
     * HTTP/1.1 204 No Content
353
     *
354
     * @param string $name
355
     * @param string $id
356
     * @param bool   $force
357
     *
358
     * @return Response
359
     */
360
    public function delete(?string $id = null, ?string $name = null, bool $force = false): Response
361
    {
362
        $group = $this->_getGroup($id, $name, true);
363
        $group->delete($force);
364
365
        return (new Response())->setCode(204);
366
    }
367
368
    /**
369
     * @api {post} /api/v2/groups/:id/undelete Restore group
370
     * @apiVersion 2.0.0
371
     * @apiName postUndelete
372
     * @apiUse _getGroup
373
     * @apiGroup Group
374
     * @apiPermission admin
375
     * @apiDescription Restore deleted group
376
     *
377
     * @apiExample Example usage:
378
     * curl -XPOST "https://SERVER/api/v2/groups/544627ed3c58891f058b4611/undelete"
379
     * curl -XPOST "https://SERVER/api/v2/groups/undelete?group=logingroup"
380
     *
381
     * @apiSuccessExample {json} Success-Response:
382
     * HTTP/1.1 204 No Content
383
     *
384
     * @param string $name
385
     * @param string $id
386
     *
387
     * @return Response
388
     */
389
    public function postUndelete(?string $id = null, ?string $name = null): Response
390
    {
391
        $this->_getGroup($id, $name, true)->undelete();
392
393
        return (new Response())->setCode(204);
394
    }
395
}
396