Completed
Branch dev (276354)
by Raffael
15:43
created

Groups::getMember()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 11
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 6
nc 2
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\AttributeDecorator\Pager;
15
use Balloon\Server;
16
use Balloon\Server\AttributeDecorator;
17
use Balloon\Server\Group;
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\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 bool   $require_admin
111
     *
112
     * @return Group
113
     */
114
    public function _getGroup(string $id, bool $require_admin = false): Group
115
    {
116
        if (true === $require_admin && !$this->user->isAdmin()) {
117
            throw new Exception\NotAdmin('submitted parameters require admin privileges');
118
        }
119
120
        return $this->server->getGroupById(new ObjectId($id));
121
    }
122
123
    /**
124
     * @api {get} /api/v2/groups/:id/members Get group member
125
     * @apiVersion 2.0.0
126
     * @apiName getMember
127
     * @apiUse _getGroup
128
     * @apiGroup Group
129
     * @apiPermission none
130
     * @apiDescription Request all member of a group
131
     *
132
     * @apiExample Example usage:
133
     * curl -XGET "https://SERVER/api/v2/groups/member?pretty"
134
     * curl -XGET "https://SERVER/api/v2/groups/544627ed3c58891f058b4611/member?pretty"
135
     * curl -XGET "https://SERVER/api/v2/groups/member?name=logingroup&pretty"
136
     *
137
     * @apiSuccess {object[]} - List of user
138
     * @apiSuccess {string} -.id User ID
139
     * @apiSuccess {string} -.name Username
140
     * @apiSuccess {string} -.mail Mail address
141
     * @apiSuccessExample {json} Success-Response:
142
     * HTTP/1.1 200 OK
143
     * [
144
     *  {
145
     *      "id": "544627ed3c58891f058b4613",
146
     *      "name": "ted",
147
     *      "mail": "[email protected]"
148
     *  }
149
     * ]
150
     *
151
     * @param string $id
152
     * @param array  $attributes
153
     */
154
    public function getMembers(string $id, array $attributes = [], int $offset = 0, int $limit = 20): Response
155
    {
156
        $group = $this->_getGroup($id);
157
        $result = $group->getResolvedMembers($offset, $limit);
158
        $uri = '/api/v2/groups/'.$group->getId().'/members';
159
        $pager = new Pager($this->decorator, $result, $attributes, $offset, $limit, $uri);
0 ignored issues
show
Documentation introduced by
$result is of type object<Generator>, but the function expects a object<Balloon\AttributeDecorator\iterable>.

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...
160
        $result = $pager->paging();
161
162
        return (new Response())->setCode(200)->setBody($result);
163
    }
164
165
    /**
166
     * @api {get} /api/v2/groups/:id Get group attributes
167
     * @apiVersion 2.0.0
168
     * @apiName get
169
     * @apiUse _getGroup
170
     * @apiGroup Group
171
     * @apiPermission none
172
     * @apiDescription Get group attributes
173
     *
174
     * @apiExample Example usage:
175
     * curl -XGET "https://SERVER/api/v2/groups/attributes?pretty"
176
     * curl -XGET "https://SERVER/api/v2/groups/544627ed3c58891f058b4611/attributes?pretty"
177
     * curl -XGET "https://SERVER/api/v2/groups/attributes?name=loginser&pretty"
178
     *
179
     * @apiSuccess (200 OK) {string} id group ID
180
     * @apiSuccess (200 OK) {string} name group name
181
     *
182
     * @apiSuccessExample {json} Success-Response:
183
     * HTTP/1.1 200 OK
184
     * {
185
     *      "id": "544627ed3c58891f058b46cd",
186
     *      "name": "test"
187
     * }
188
     *
189
     * @param string $id
190
     * @param string $attributes
191
     *
192
     * @return Response
193
     */
194
    public function get(?string $id = null, array $query = [], array $attributes = [], int $offset = 0, int $limit = 20): Response
195
    {
196
        if ($id === null) {
197
            $result = $this->server->getGroups($query, $offset, $limit);
198
            $pager = new Pager($this->decorator, $result, $attributes, $offset, $limit, '/api/v2/groups');
0 ignored issues
show
Documentation introduced by
$result is of type object<Generator>, but the function expects a object<Balloon\AttributeDecorator\iterable>.

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...
199
            $result = $pager->paging();
200
        } else {
201
            $result = $this->decorator->decorate($this->_getGroup($id), $attributes);
202
        }
203
204
        return (new Response())->setCode(200)->setBody($result);
205
    }
206
207
    /**
208
     * @api {head} /api/v2/groups/:id Group exists
209
     * @apiVersion 2.0.0
210
     * @apiName postQuota
211
     * @apiUse _getGroup
212
     * @apiGroup Group
213
     * @apiPermission admin
214
     * @apiDescription Check if group account exists
215
     *
216
     * @apiExample Example usage:
217
     * curl -XHEAD "https://SERVER/api/v2/group"
218
     * curl -XHEAD "https://SERVER/api/v2/groups/544627ed3c58891f058b4611"
219
     * curl -XHEAD "https://SERVER/api/v2/group?name=logingroup"
220
     *
221
     * @apiSuccessExample {json} Success-Response:
222
     * HTTP/1.1 204 No Content
223
     *
224
     * @param string $id
225
     *
226
     * @return Response
227
     */
228
    public function head(string $id): Response
229
    {
230
        $result = $this->_getGroup($id, 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...
231
232
        return (new Response())->setCode(204);
233
    }
234
235
    /**
236
     * @api {post} /api/v2/groups Create group
237
     * @apiVersion 2.0.0
238
     * @apiName postGroup
239
     * @apiGroup Group
240
     * @apiPermission admin
241
     * @apiDescription Create group
242
     *
243
     * @apiExample Example usage:
244
     * curl -XPOST "https://SERVER/api/v2/group"
245
     *
246
     * @apiParam (POST Parameter) {string} name group name
247
     * @apiParam (POST Parameter) {string[]} member Array of member id
248
     * @apiParam (POST Parameter) {string} namespace Namespace
249
     * @apiParam (POST Parameter) {string[]} optional Optional attributes
250
     *
251
     * @apiSuccess (200 OK) {string} id group ID
252
     * @apiSuccess (200 OK) {string} name group name
253
     *
254
     * @apiSuccessExample {json} Success-Response:
255
     * HTTP/1.1 201 Created
256
     * {
257
     *      "id": "544627ed3c58891f058b46cd",
258
     *      "name": "test"
259
     * }
260
     *
261
     * @param string $name
262
     * @param array  $member
263
     *
264
     * @return Response
265
     */
266
    public function post(string $name, ?array $member = null, ?string $namespace = null, ?array $optional = null): Response
267
    {
268
        if (!$this->user->isAdmin()) {
269
            throw new Exception\NotAdmin('submitted parameters require admin privileges');
270
        }
271
272
        $attributes = compact('namespace', 'optional');
273
        $attributes = array_filter($attributes, function ($attribute) {return !is_null($attribute); });
274
275
        $id = $this->server->addGroup($name, $member, $attributes);
0 ignored issues
show
Bug introduced by
It seems like $member defined by parameter $member on line 266 can also be of type null; however, Balloon\Server::addGroup() does only seem to accept array, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
276
        $result = $this->decorator->decorate($this->server->getGroupById($id));
277
278
        return (new Response())->setBody($result)->setCode(201);
279
    }
280
281
    /**
282
     * @api {patch} /api/v2/groups/:id Change group attributes
283
     * @apiVersion 2.0.0
284
     * @apiName patch
285
     * @apiUse _getGroup
286
     * @apiGroup Group
287
     * @apiPermission admin
288
     * @apiDescription Set attributes for group
289
     *
290
     * @apiParam (POST Parameter) {string} name group name
291
     * @apiParam (POST Parameter) {string[]} member Array of member id
292
     * @apiParam (POST Parameter) {string} namespace Namespace
293
     * @apiParam (POST Parameter) {string[]} optional Optional attributes
294
     *
295
     * @apiExample Example usage:
296
     * curl -XPOST "https://SERVER/api/v2/groups/attributes" -d '{"attributes": ["mail": "[email protected]"]}'
297
     * curl -XPOST "https://SERVER/api/v2/groups/attributes?{%22attributes%22:[%22mail%22:%[email protected]%22]}""
298
     * curl -XPOST "https://SERVER/api/v2/groups/544627ed3c58891f058b4611/attributes" -d '{"attributes": ["admin": "false"]}'
299
     * curl -XPOST "https://SERVER/api/v2/groups/quota?name=logingroup"  -d '{"attributes": ["admin": "false"]}'
300
     *
301
     * @apiSuccessExample {json} Success-Response:
302
     * HTTP/1.1 200 OK
303
     *
304
     * @param string $id
305
     * @param array  $attributes
0 ignored issues
show
Bug introduced by
There is no parameter named $attributes. 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...
306
     *
307
     * @return Response
308
     */
309
    public function patch(string $id, ?array $member = null, ?string $namespace = null, ?array $optional = null): Response
310
    {
311
        $attributes = compact('namespace', 'optional', 'name', 'member');
312
        $attributes = array_filter($attributes, function ($attribute) {return !is_null($attribute); });
313
314
        $group = $this->_getGroup($id, true)->setAttributes($attributes);
315
        $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...
316
317
        return (new Response())->setCode(200)->setBody($result);
318
    }
319
320
    /**
321
     * @api {delete} /api/v2/groups/:id Delete group
322
     * @apiVersion 2.0.0
323
     * @apiName delete
324
     * @apiUse _getGroup
325
     * @apiGroup Group
326
     * @apiPermission admin
327
     * @apiDescription Delete group
328
     *
329
     * @apiExample Example usage:
330
     * curl -XDELETE "https://SERVER/api/v2/groups/544627ed3c58891f058b4611?force=1"
331
     * curl -XDELETE "https://SERVER/api/v2/group?name=logingroup"
332
     *
333
     * @apiParam (GET Parameter) {bool} [force=false] Per default the group gets disabled, if force is set
334
     * the group gets removed completely.
335
     *
336
     * @apiErrorExample {json} Error-Response (Can not delete yourself):
337
     * HTTP/1.1 400 Bad Request
338
     * {
339
     *      "status": 400,
340
     *      "data": {
341
     *          "error": "Balloon\\Exception\\Conflict",
342
     *          "message": "requested group was not found"
343
     *      }
344
     * }
345
     *
346
     * @apiSuccessExample {json} Success-Response:
347
     * HTTP/1.1 204 No Content
348
     *
349
     * @param string $id
350
     * @param bool   $force
351
     *
352
     * @return Response
353
     */
354
    public function delete(string $id, bool $force = false): Response
355
    {
356
        $group = $this->_getGroup($id, true);
357
        $group->delete($force);
358
359
        return (new Response())->setCode(204);
360
    }
361
362
    /**
363
     * @api {post} /api/v2/groups/:id/undelete Restore group
364
     * @apiVersion 2.0.0
365
     * @apiName postUndelete
366
     * @apiUse _getGroup
367
     * @apiGroup Group
368
     * @apiPermission admin
369
     * @apiDescription Restore deleted group
370
     *
371
     * @apiExample Example usage:
372
     * curl -XPOST "https://SERVER/api/v2/groups/544627ed3c58891f058b4611/undelete"
373
     * curl -XPOST "https://SERVER/api/v2/groups/undelete?group=logingroup"
374
     *
375
     * @apiSuccessExample {json} Success-Response:
376
     * HTTP/1.1 204 No Content
377
     *
378
     * @param string $id
379
     *
380
     * @return Response
381
     */
382
    public function postUndelete(string $id): Response
383
    {
384
        $this->_getGroup($id, true)->undelete();
385
386
        return (new Response())->setCode(204);
387
    }
388
}
389