Completed
Push — master ( 287393...7ff50d )
by Raffael
18:27 queued 14:12
created

src/app/Balloon.App.Api/v2/Groups.php (3 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * balloon
7
 *
8
 * @copyright   Copryright (c) 2012-2019 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
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 function MongoDB\BSON\fromJSON;
22
use MongoDB\BSON\ObjectId;
23
use function MongoDB\BSON\toPHP;
24
25
class Groups
26
{
27
    /**
28
     * User.
29
     *
30
     * @var User
31
     */
32
    protected $user;
33
34
    /**
35
     * Server.
36
     *
37
     * @var Server
38
     */
39
    protected $server;
40
41
    /**
42
     * Attribute decorator.
43
     *
44
     * @var AttributeDecorator
45
     */
46
    protected $decorator;
47
48
    /**
49
     * Initialize.
50
     *
51
     * @param AttributeDecorator
52
     */
53
    public function __construct(Server $server, AttributeDecorator $decorator)
54
    {
55
        $this->user = $server->getIdentity();
56
        $this->server = $server;
57
        $this->decorator = $decorator;
58
    }
59
60
    /**
61
     * @apiDefine _getGroup
62
     *
63
     * @apiParam (GET Parameter) {string[]} id Either a single id (group id) or a name (groupname) must be given (admin privilege required).
64
     * @apiParam (GET Parameter) {string[]} name Either a single id (group id) or a name (groupname) must be given (admin privilege required).
65
     *
66
     * @apiErrorExample {json} Error-Response (No admin privileges):
67
     * HTTP/1.1 403 Forbidden
68
     * {
69
     *      "status": 403,
70
     *      "data": {
71
     *          "error": "Balloon\\Exception\\Forbidden",
72
     *          "message": "submitted parameters require to have admin privileges",
73
     *          "code": 41
74
     *      }
75
     * }
76
     *
77
     * @apiErrorExample {json} Error-Response (Group not found):
78
     * HTTP/1.1 404 Not Found
79
     * {
80
     *      "status": 404,
81
     *      "data": {
82
     *          "error": "Balloon\\Exception\\NotFound",
83
     *          "message": "requested group was not found",
84
     *          "code": 53
85
     *      }
86
     * }
87
     *
88
     * @apiErrorExample {json} Error-Response (Invalid argument):
89
     * HTTP/1.1 400 Bad Request
90
     * {
91
     *      "status": 400,
92
     *      "data": {
93
     *          "error": "Balloon\\Exception\\InvalidArgument",
94
     *          "message": "provide either id (group id) or name (groupname)",
95
     *          "Code": 0
96
     *      }
97
     * }
98
     */
99
100
    /**
101
     * @apiDefine _getGroups
102
     *
103
     * @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.
104
     * @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.
105
     */
106
107
    /**
108
     * Get group instance.
109
     */
110
    public function _getGroup(string $id, bool $require_admin = false): Group
111
    {
112
        if (true === $require_admin && !$this->user->isAdmin()) {
113
            throw new Exception\NotAdmin('submitted parameters require admin privileges');
114
        }
115
116
        return $this->server->getGroupById(new ObjectId($id));
117
    }
118
119
    /**
120
     * @api {get} /api/v2/groups/:id/members Get group member
121
     * @apiVersion 2.0.0
122
     * @apiName getMember
123
     * @apiUse _getGroup
124
     * @apiGroup Group
125
     * @apiPermission none
126
     * @apiDescription Request all member of a group
127
     *
128
     * @apiExample Example usage:
129
     * curl -XGET "https://SERVER/api/v2/groups/member?pretty"
130
     * curl -XGET "https://SERVER/api/v2/groups/544627ed3c58891f058b4611/member?pretty"
131
     * curl -XGET "https://SERVER/api/v2/groups/member?name=logingroup&pretty"
132
     *
133
     * @apiSuccess {object[]} - List of user
134
     * @apiSuccess {string} -.id User ID
135
     * @apiSuccess {string} -.name Username
136
     * @apiSuccess {string} -.mail Mail address
137
     * @apiSuccessExample {json} Success-Response:
138
     * HTTP/1.1 200 OK
139
     * [
140
     *  {
141
     *      "id": "544627ed3c58891f058b4613",
142
     *      "name": "ted",
143
     *      "mail": "[email protected]"
144
     *  }
145
     * ]
146
     */
147
    public function getMembers(string $id, array $attributes = [], int $offset = 0, int $limit = 20): Response
148
    {
149
        $group = $this->_getGroup($id);
150
        $result = $group->getResolvedMembers($offset, $limit);
151
        $uri = '/api/v2/groups/'.$group->getId().'/members';
152
        $pager = new Pager($this->decorator, $result, $attributes, $offset, $limit, $uri);
153
        $result = $pager->paging();
154
155
        return (new Response())->setCode(200)->setBody($result);
156
    }
157
158
    /**
159
     * @api {get} /api/v2/groups/:id Get group attributes
160
     * @apiVersion 2.0.0
161
     * @apiName get
162
     * @apiUse _getGroup
163
     * @apiGroup Group
164
     * @apiPermission none
165
     * @apiDescription Get group attributes
166
     *
167
     * @apiExample Example usage:
168
     * curl -XGET "https://SERVER/api/v2/groups/attributes?pretty"
169
     * curl -XGET "https://SERVER/api/v2/groups/544627ed3c58891f058b4611/attributes?pretty"
170
     * curl -XGET "https://SERVER/api/v2/groups/attributes?name=loginser&pretty"
171
     *
172
     * @apiSuccess (200 OK) {string} id group ID
173
     * @apiSuccess (200 OK) {string} name group name
174
     *
175
     * @apiSuccessExample {json} Success-Response:
176
     * HTTP/1.1 200 OK
177
     * {
178
     *      "id": "544627ed3c58891f058b46cd",
179
     *      "name": "test"
180
     * }
181
     *
182
     * @param string     $id
183
     * @param string     $attributes
184
     * @param null|mixed $query
185
     */
186
    public function get(?string $id = null, $query = null, array $attributes = [], int $offset = 0, int $limit = 20): Response
187
    {
188
        if ($id === null) {
189
            if ($query === null) {
190
                $query = [];
191
            } elseif (is_string($query)) {
192
                $query = toPHP(fromJSON($query), [
193
                    'root' => 'array',
194
                    'document' => 'array',
195
                    'array' => 'array',
196
                ]);
197
            }
198
199
            $result = $this->server->getGroups($query, $offset, $limit);
200
            $pager = new Pager($this->decorator, $result, $attributes, $offset, $limit, '/api/v2/groups');
201
            $result = $pager->paging();
202
        } else {
203
            $result = $this->decorator->decorate($this->_getGroup($id), $attributes);
204
        }
205
206
        return (new Response())->setCode(200)->setBody($result);
207
    }
208
209
    /**
210
     * @api {head} /api/v2/groups/:id Group exists
211
     * @apiVersion 2.0.0
212
     * @apiName postQuota
213
     * @apiUse _getGroup
214
     * @apiGroup Group
215
     * @apiPermission admin
216
     * @apiDescription Check if group account exists
217
     *
218
     * @apiExample Example usage:
219
     * curl -XHEAD "https://SERVER/api/v2/group"
220
     * curl -XHEAD "https://SERVER/api/v2/groups/544627ed3c58891f058b4611"
221
     * curl -XHEAD "https://SERVER/api/v2/group?name=logingroup"
222
     *
223
     * @apiSuccessExample {json} Success-Response:
224
     * HTTP/1.1 204 No Content
225
     */
226
    public function head(string $id): Response
227
    {
228
        $result = $this->_getGroup($id, true);
0 ignored issues
show
$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...
229
230
        return (new Response())->setCode(204);
231
    }
232
233
    /**
234
     * @api {post} /api/v2/groups Create group
235
     * @apiVersion 2.0.0
236
     * @apiName postGroup
237
     * @apiGroup Group
238
     * @apiPermission admin
239
     * @apiDescription Create group
240
     *
241
     * @apiExample Example usage:
242
     * curl -XPOST "https://SERVER/api/v2/group"
243
     *
244
     * @apiParam (POST Parameter) {string} name group name
245
     * @apiParam (POST Parameter) {string[]} member Array of member id
246
     * @apiParam (POST Parameter) {string} namespace Namespace
247
     * @apiParam (POST Parameter) {string[]} optional Optional attributes
248
     *
249
     * @apiSuccess (200 OK) {string} id group ID
250
     * @apiSuccess (200 OK) {string} name group name
251
     *
252
     * @apiSuccessExample {json} Success-Response:
253
     * HTTP/1.1 201 Created
254
     * {
255
     *      "id": "544627ed3c58891f058b46cd",
256
     *      "name": "test"
257
     * }
258
     *
259
     * @param array $member
260
     */
261
    public function post(string $name, ?array $member = null, ?string $namespace = null, ?array $optional = null): Response
262
    {
263
        if (!$this->user->isAdmin()) {
264
            throw new Exception\NotAdmin('submitted parameters require admin privileges');
265
        }
266
267
        $attributes = compact('namespace', 'optional');
268
        $attributes = array_filter($attributes, function ($attribute) {return !is_null($attribute); });
269
270
        $id = $this->server->addGroup($name, $member, $attributes);
0 ignored issues
show
It seems like $member defined by parameter $member on line 261 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...
271
        $result = $this->decorator->decorate($this->server->getGroupById($id));
272
273
        return (new Response())->setBody($result)->setCode(201);
274
    }
275
276
    /**
277
     * @api {patch} /api/v2/groups/:id Change group attributes
278
     * @apiVersion 2.0.0
279
     * @apiName patch
280
     * @apiUse _getGroup
281
     * @apiGroup Group
282
     * @apiPermission admin
283
     * @apiDescription Set attributes for group
284
     *
285
     * @apiParam (POST Parameter) {string} name group name
286
     * @apiParam (POST Parameter) {string[]} member Array of member id
287
     * @apiParam (POST Parameter) {string} namespace Namespace
288
     * @apiParam (POST Parameter) {string[]} optional Optional attributes
289
     *
290
     * @apiExample Example usage:
291
     * curl -XPOST "https://SERVER/api/v2/groups/attributes" -d '{"attributes": ["mail": "[email protected]"]}'
292
     * curl -XPOST "https://SERVER/api/v2/groups/attributes?{%22attributes%22:[%22mail%22:%[email protected]%22]}""
293
     * curl -XPOST "https://SERVER/api/v2/groups/544627ed3c58891f058b4611/attributes" -d '{"attributes": ["admin": "false"]}'
294
     * curl -XPOST "https://SERVER/api/v2/groups/quota?name=logingroup"  -d '{"attributes": ["admin": "false"]}'
295
     *
296
     * @apiSuccessExample {json} Success-Response:
297
     * HTTP/1.1 200 OK
298
     */
299
    public function patch(string $id, ?array $member = null, ?string $namespace = null, ?array $optional = null): Response
300
    {
301
        $attributes = compact('namespace', 'optional', 'name', 'member');
302
        $attributes = array_filter($attributes, function ($attribute) {return !is_null($attribute); });
303
304
        $group = $this->_getGroup($id, true);
305
        $group->setAttributes($attributes);
306
        $result = $this->decorator->decorate($group);
307
308
        return (new Response())->setCode(200)->setBody($result);
309
    }
310
311
    /**
312
     * @api {delete} /api/v2/groups/:id Delete group
313
     * @apiVersion 2.0.0
314
     * @apiName delete
315
     * @apiUse _getGroup
316
     * @apiGroup Group
317
     * @apiPermission admin
318
     * @apiDescription Delete group
319
     *
320
     * @apiExample Example usage:
321
     * curl -XDELETE "https://SERVER/api/v2/groups/544627ed3c58891f058b4611?force=1"
322
     * curl -XDELETE "https://SERVER/api/v2/group?name=logingroup"
323
     *
324
     * @apiParam (GET Parameter) {bool} [force=false] Per default the group gets disabled, if force is set
325
     * the group gets removed completely.
326
     *
327
     * @apiErrorExample {json} Error-Response (Can not delete yourself):
328
     * HTTP/1.1 400 Bad Request
329
     * {
330
     *      "status": 400,
331
     *      "data": {
332
     *          "error": "Balloon\\Exception\\Conflict",
333
     *          "message": "requested group was not found"
334
     *      }
335
     * }
336
     *
337
     * @apiSuccessExample {json} Success-Response:
338
     * HTTP/1.1 204 No Content
339
     */
340
    public function delete(string $id, bool $force = false): Response
341
    {
342
        $group = $this->_getGroup($id, true);
343
        $group->delete($force);
344
345
        return (new Response())->setCode(204);
346
    }
347
348
    /**
349
     * @api {post} /api/v2/groups/:id/undelete Restore group
350
     * @apiVersion 2.0.0
351
     * @apiName postUndelete
352
     * @apiUse _getGroup
353
     * @apiGroup Group
354
     * @apiPermission admin
355
     * @apiDescription Restore deleted group
356
     *
357
     * @apiExample Example usage:
358
     * curl -XPOST "https://SERVER/api/v2/groups/544627ed3c58891f058b4611/undelete"
359
     * curl -XPOST "https://SERVER/api/v2/groups/undelete?group=logingroup"
360
     *
361
     * @apiSuccessExample {json} Success-Response:
362
     * HTTP/1.1 204 No Content
363
     */
364
    public function postUndelete(string $id): Response
365
    {
366
        $this->_getGroup($id, true)->undelete();
367
368
        return (new Response())->setCode(204);
369
    }
370
}
371