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\v1; |
||
13 | |||
14 | use Balloon\Server; |
||
15 | use Balloon\Server\AttributeDecorator; |
||
16 | use Balloon\Server\User\Exception; |
||
17 | use Micro\Http\Response; |
||
18 | use MongoDB\BSON\ObjectId; |
||
19 | |||
20 | class User |
||
21 | { |
||
22 | /** |
||
23 | * User. |
||
24 | * |
||
25 | * @var User |
||
26 | */ |
||
27 | protected $user; |
||
28 | |||
29 | /** |
||
30 | * Server. |
||
31 | * |
||
32 | * @var Server |
||
33 | */ |
||
34 | protected $server; |
||
35 | |||
36 | /** |
||
37 | * Decorator. |
||
38 | * |
||
39 | * @var AttributeDecorator |
||
40 | */ |
||
41 | protected $decorator; |
||
42 | |||
43 | /** |
||
44 | * Initialize. |
||
45 | */ |
||
46 | public function __construct(Server $server, AttributeDecorator $decorator) |
||
47 | { |
||
48 | $this->user = $server->getIdentity(); |
||
0 ignored issues
–
show
|
|||
49 | $this->server = $server; |
||
50 | $this->decorator = $decorator; |
||
51 | } |
||
52 | |||
53 | /** |
||
54 | * @apiDefine _getUser |
||
55 | * |
||
56 | * @apiParam (GET Parameter) {string[]} uid Either a single uid (user id) or a uname (username) must be given (admin privilege required). |
||
57 | * @apiParam (GET Parameter) {string[]} uname Either a single uid (user id) or a uname (username) must be given (admin privilege required). |
||
58 | * |
||
59 | * @apiErrorExample {json} Error-Response (No admin privileges): |
||
60 | * HTTP/1.1 403 Forbidden |
||
61 | * { |
||
62 | * "status": 403, |
||
63 | * "data": { |
||
64 | * "error": "Balloon\\Filesystem\\Acl\\Exception\\Forbidden", |
||
65 | * "message": "submitted parameters require to have admin privileges", |
||
66 | * "code": 41 |
||
67 | * } |
||
68 | * } |
||
69 | * |
||
70 | * @apiErrorExample {json} Error-Response (User not found): |
||
71 | * HTTP/1.1 404 Not Found |
||
72 | * { |
||
73 | * "status": 404, |
||
74 | * "data": { |
||
75 | * "error": "Balloon\\Server\\User\\Exception", |
||
76 | * "message": "requested user was not found", |
||
77 | * "code": 53 |
||
78 | * } |
||
79 | * } |
||
80 | * |
||
81 | * @apiErrorExample {json} Error-Response (Invalid argument): |
||
82 | * HTTP/1.1 400 Bad Request |
||
83 | * { |
||
84 | * "status": 400, |
||
85 | * "data": { |
||
86 | * "error": "Balloon\\Exception\\InvalidArgument", |
||
87 | * "message": "provide either uid (user id) or uname (username)", |
||
88 | * "Code": 0 |
||
89 | * } |
||
90 | * } |
||
91 | */ |
||
92 | |||
93 | /** |
||
94 | * @apiDefine _getUsers |
||
95 | * |
||
96 | * @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. |
||
97 | * @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. |
||
98 | */ |
||
99 | |||
100 | /** |
||
101 | * Get user instance. |
||
102 | * |
||
103 | * @param string $id |
||
104 | * @param string $uname |
||
105 | * |
||
106 | * @return User |
||
107 | */ |
||
108 | public function _getUser(?string $id = null, ?string $uname = null, bool $require_admin = false) |
||
109 | { |
||
110 | if (null !== $id || null !== $uname || true === $require_admin) { |
||
111 | if ($this->user->isAdmin()) { |
||
0 ignored issues
–
show
The method
isAdmin() does not seem to exist on object<Balloon\App\Api\v1\User> .
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed.
Loading history...
|
|||
112 | if (null !== $id && null !== $uname) { |
||
113 | throw new Exception\InvalidArgument( |
||
114 | 'provide either id (user id) or uname (username)', |
||
115 | Exception\InvalidArgument::IDENTIFIER_NOT_UNIQUE |
||
116 | ); |
||
117 | } |
||
118 | |||
119 | if (null !== $id) { |
||
120 | return $this->server->getUserById(new ObjectId($id)); |
||
0 ignored issues
–
show
The return type of
return $this->server->ge...DB\BSON\ObjectId($id)); (Balloon\Server\User ) is incompatible with the return type documented by Balloon\App\Api\v1\User::_getUser of type Balloon\App\Api\v1\User .
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design. Let’s take a look at an example: class Author {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
abstract class Post {
public function getAuthor() {
return 'Johannes';
}
}
class BlogPost extends Post {
public function getAuthor() {
return new Author('Johannes');
}
}
class ForumPost extends Post { /* ... */ }
function my_function(Post $post) {
echo strtoupper($post->getAuthor());
}
Our function
Loading history...
|
|||
121 | } |
||
122 | |||
123 | return $this->server->getUserByName($uname); |
||
0 ignored issues
–
show
The return type of
return $this->server->getUserByName($uname); (Balloon\Server\User ) is incompatible with the return type documented by Balloon\App\Api\v1\User::_getUser of type Balloon\App\Api\v1\User .
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design. Let’s take a look at an example: class Author {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
abstract class Post {
public function getAuthor() {
return 'Johannes';
}
}
class BlogPost extends Post {
public function getAuthor() {
return new Author('Johannes');
}
}
class ForumPost extends Post { /* ... */ }
function my_function(Post $post) {
echo strtoupper($post->getAuthor());
}
Our function
Loading history...
|
|||
124 | } |
||
125 | |||
126 | throw new Exception\NotAdmin('submitted parameters require admin privileges'); |
||
127 | } |
||
128 | |||
129 | return $this->user; |
||
130 | } |
||
131 | |||
132 | /** |
||
133 | * @api {get} /api/v1/user/groups Group membership |
||
134 | * @apiVersion 1.0.0 |
||
135 | * @apiName getGroups |
||
136 | * @apiUse _getUser |
||
137 | * @apiGroup User |
||
138 | * @apiPermission none |
||
139 | * @apiDescription Get all user groups |
||
140 | * If you want to receive your own groups you have to leave the parameters uid and uname empty. |
||
141 | * Requesting this api with parameter uid or uname requires admin privileges. |
||
142 | * |
||
143 | * @apiExample Example usage: |
||
144 | * curl -XGET "https://SERVER/api/v1/user/groups?pretty" |
||
145 | * curl -XGET "https://SERVER/api/v1/user/544627ed3c58891f058b4611/groups?pretty" |
||
146 | * curl -XGET "https://SERVER/api/v1/user/groups?uname=loginuser&pretty" |
||
147 | * |
||
148 | * @apiSuccess {number} status Status Code |
||
149 | * @apiSuccess {string[]} data All groups with membership |
||
150 | * @apiSuccessExample {json} Success-Response: |
||
151 | * HTTP/1.1 200 OK |
||
152 | * { |
||
153 | * "status": 200, |
||
154 | * "data": [ |
||
155 | * "group1", |
||
156 | * "group2", |
||
157 | * ] |
||
158 | * } |
||
159 | * |
||
160 | * @param string $uid |
||
161 | * @param string $uname |
||
162 | */ |
||
163 | public function getGroups(?string $uid = null, ?string $uname = null): Response |
||
164 | { |
||
165 | $result = $this->_getUser($uid, $uname)->getGroups(); |
||
166 | |||
167 | return (new Response())->setCode(200)->setBody([ |
||
168 | 'status' => 200, |
||
169 | 'data' => $result, |
||
170 | ]); |
||
171 | } |
||
172 | |||
173 | /** |
||
174 | * @api {get} /api/v1/user/shares Share membership |
||
175 | * @apiVersion 1.0.0 |
||
176 | * @apiName getShares |
||
177 | * @apiUse _getUser |
||
178 | * @apiGroup User |
||
179 | * @apiPermission none |
||
180 | * @apiDescription Get all shares |
||
181 | * If you want to receive your own shares (member or owner) you have to leave the parameters uid and uname empty. |
||
182 | * Requesting this api with parameter uid or uname requires admin privileges. |
||
183 | * |
||
184 | * @apiExample Example usage: |
||
185 | * curl -XGET "https://SERVER/api/v1/user/shares?pretty" |
||
186 | * curl -XGET "https://SERVER/api/v1/user/544627ed3c58891f058b4611/shares?pretty" |
||
187 | * curl -XGET "https://SERVER/api/v1/user/shares?uname=loginuser&pretty" |
||
188 | * |
||
189 | * @apiSuccess {number} status Status Code |
||
190 | * @apiSuccess {string[]} data All shares with membership |
||
191 | * @apiSuccessExample {json} Success-Response: |
||
192 | * HTTP/1.1 200 OK |
||
193 | * { |
||
194 | * "status": 200, |
||
195 | * "data": [ |
||
196 | * "shareid1", |
||
197 | * "shareid2", |
||
198 | * ] |
||
199 | * } |
||
200 | * |
||
201 | * @param string $uid |
||
202 | * @param string $uname |
||
203 | */ |
||
204 | public function getShares(?string $uid = null, ?string $uname = null): Response |
||
205 | { |
||
206 | $result = $this->_getUser($uid, $uname)->getShares(); |
||
207 | |||
208 | return (new Response())->setCode(200)->setBody([ |
||
209 | 'status' => 200, |
||
210 | 'data' => $result, |
||
211 | ]); |
||
212 | } |
||
213 | |||
214 | /** |
||
215 | * @api {get} /api/v1/user/quota-usage Quota usage |
||
216 | * @apiVersion 1.0.0 |
||
217 | * @apiName getQuotaUsage |
||
218 | * @apiUse _getUser |
||
219 | * @apiGroup User |
||
220 | * @apiPermission none |
||
221 | * @apiDescription Get user quota usage (including hard,soft,used and available space). |
||
222 | * If you want to receive your own quota you have to leave the parameters uid and uname empty. |
||
223 | * Requesting this api with parameter uid or uname requires admin privileges. |
||
224 | * |
||
225 | * @apiExample Example usage: |
||
226 | * curl -XGET "https://SERVER/api/v1/user/quota-usage?pretty" |
||
227 | * curl -XGET "https://SERVER/api/v1/user/544627ed3c58891f058b4611/quota-usage?pretty" |
||
228 | * curl -XGET "https://SERVER/api/v1/user/quota-usage?uname=loginuser&pretty" |
||
229 | * |
||
230 | * @apiSuccess {number} status Status Code |
||
231 | * @apiSuccess {object} data Quota stats |
||
232 | * @apiSuccess {number} data.used Used quota in bytes |
||
233 | * @apiSuccess {number} data.available Quota left in bytes |
||
234 | * @apiSuccess {number} data.hard_quota Hard quota in bytes |
||
235 | * @apiSuccess {number} data.soft_quota Soft quota (Warning) in bytes |
||
236 | * @apiSuccessExample {json} Success-Response: |
||
237 | * HTTP/1.1 200 OK |
||
238 | * { |
||
239 | * "status": 200, |
||
240 | * "data": { |
||
241 | * "used": 15543092, |
||
242 | * "available": 5353166028, |
||
243 | * "hard_quota": 5368709120, |
||
244 | * "soft_quota": 5368709120 |
||
245 | * } |
||
246 | * } |
||
247 | * |
||
248 | * @param string $uid |
||
249 | * @param string $uname |
||
250 | */ |
||
251 | public function getQuotaUsage(?string $uid = null, ?string $uname = null): Response |
||
252 | { |
||
253 | $result = $this->_getUser($uid, $uname)->getQuotaUsage(); |
||
254 | |||
255 | return (new Response())->setCode(200)->setBody([ |
||
256 | 'status' => 200, |
||
257 | 'data' => $result, |
||
258 | ]); |
||
259 | } |
||
260 | |||
261 | /** |
||
262 | * @api {get} /api/v1/user/attributes User attributes |
||
263 | * @apiVersion 1.0.0 |
||
264 | * @apiName getAttributes |
||
265 | * @apiUse _getUser |
||
266 | * @apiGroup User |
||
267 | * @apiPermission none |
||
268 | * @apiDescription Get all user attributes including username, mail, id,.... |
||
269 | * If you want to receive your own attributes you have to leave the parameters uid and uname empty. |
||
270 | * Requesting this api with parameter uid or uname requires admin privileges. |
||
271 | * |
||
272 | * @apiExample Example usage: |
||
273 | * curl -XGET "https://SERVER/api/v1/user/attributes?pretty" |
||
274 | * curl -XGET "https://SERVER/api/v1/user/544627ed3c58891f058b4611/attributes?pretty" |
||
275 | * curl -XGET "https://SERVER/api/v1/user/attributes?uname=loginser&pretty" |
||
276 | * |
||
277 | * @apiSuccess (200 OK) {number} status Status Code |
||
278 | * @apiSuccess (200 OK) {object[]} user attributes |
||
279 | * |
||
280 | * @apiSuccessExample {json} Success-Response: |
||
281 | * HTTP/1.1 200 OK |
||
282 | * { |
||
283 | * "status": 200, |
||
284 | * "data": [] //shortened |
||
285 | * } |
||
286 | * |
||
287 | * @param string $uid |
||
288 | * @param string $uname |
||
289 | * @param string $attributes |
||
290 | */ |
||
291 | public function getAttributes(?string $uid = null, ?string $uname = null, array $attributes = []): Response |
||
292 | { |
||
293 | $result = $this->decorator->decorate($this->_getUser($uid, $uname), $attributes); |
||
294 | |||
295 | return (new Response())->setCode(200)->setBody([ |
||
296 | 'status' => 200, |
||
297 | 'data' => $result, |
||
298 | ]); |
||
299 | } |
||
300 | |||
301 | /** |
||
302 | * @api {head} /api/v1/user?uid=:uid User exists? |
||
303 | * @apiVersion 1.0.0 |
||
304 | * @apiName postQuota |
||
305 | * @apiUse _getUser |
||
306 | * @apiGroup User |
||
307 | * @apiPermission admin |
||
308 | * @apiDescription Check if user account exists |
||
309 | * |
||
310 | * @apiExample Example usage: |
||
311 | * curl -XHEAD "https://SERVER/api/v1/user" |
||
312 | * curl -XHEAD "https://SERVER/api/v1/user/544627ed3c58891f058b4611" |
||
313 | * curl -XHEAD "https://SERVER/api/v1/user?uname=loginuser" |
||
314 | * |
||
315 | * @apiSuccessExample {json} Success-Response: |
||
316 | * HTTP/1.1 204 No Content |
||
317 | * |
||
318 | * @param string $uname |
||
319 | * @param string $uid |
||
320 | */ |
||
321 | public function head(?string $uid = null, ?string $uname = null): Response |
||
322 | { |
||
323 | $result = $this->_getUser($uid, $uname); |
||
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
Loading history...
|
|||
324 | |||
325 | return (new Response())->setCode(204); |
||
326 | } |
||
327 | |||
328 | /** |
||
329 | * @api {get} /api/v1/user/whoami Who am I? |
||
330 | * @apiVersion 1.0.0 |
||
331 | * @apiName getWhoami |
||
332 | * @apiUse _getUser |
||
333 | * @apiGroup User |
||
334 | * @apiPermission none |
||
335 | * @apiDescription Get the username of the authenticated user |
||
336 | * If you want to receive your own username you have to leave the parameters uid and uname empty. |
||
337 | * Requesting this api with parameter uid or uname requires admin privileges. |
||
338 | * |
||
339 | * @apiExample Example usage: |
||
340 | * curl -XGET "https://SERVER/api/v2/user/whoami?pretty" |
||
341 | * |
||
342 | * @apiSuccess {number} code HTTP status code |
||
343 | * @apiSuccess {string} data Username |
||
344 | * @apiSuccessExample {json} Success-Response: |
||
345 | * HTTP/1.1 200 OK |
||
346 | * { |
||
347 | * "code": 200, |
||
348 | * "data": "user" |
||
349 | * } |
||
350 | */ |
||
351 | public function getWhoami(array $attributes = []): Response |
||
352 | { |
||
353 | return (new Response())->setCode(200)->setBody([ |
||
354 | 'status' => 200, |
||
355 | 'data' => $this->_getUser()->getUsername(), |
||
0 ignored issues
–
show
The method
getUsername() does not seem to exist on object<Balloon\App\Api\v1\User> .
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed.
Loading history...
|
|||
356 | ]); |
||
357 | } |
||
358 | |||
359 | /** |
||
360 | * @api {get} /api/v1/user/node-attribute-summary Node attribute summary |
||
361 | * @apiVersion 1.0.0 |
||
362 | * @apiName getNodeAttributeSummary |
||
363 | * @apiUse _getUser |
||
364 | * @apiGroup User |
||
365 | * @apiPermission none |
||
366 | * @apiDescription Get summary and usage of specific node attributes |
||
367 | * If you want to receive your own node summary you have to leave the parameters uid and uname empty. |
||
368 | * Requesting this api with parameter uid or uname requires admin privileges. |
||
369 | * |
||
370 | * @apiExample Example usage: |
||
371 | * curl -XGET "https://SERVER/api/v1/user/node-attribute-summary?pretty" |
||
372 | * curl -XGET "https://SERVER/api/v1/user/544627ed3c58891f058b4611/node-attribute-summary?pretty" |
||
373 | * curl -XGET "https://SERVER/api/v1/user/node-attribute-summary?uname=loginuser&pretty" |
||
374 | * |
||
375 | * @param string $id |
||
376 | * @param string $uname |
||
377 | * @param string $attributes |
||
378 | */ |
||
379 | public function getNodeAttributeSummary(?string $id = null, ?string $uname = null, array $attributes = [], int $limit = 25): Response |
||
380 | { |
||
381 | $result = $this->_getUser($id, $uname)->getNodeAttributeSummary($attributes, $limit); |
||
382 | |||
383 | return (new Response())->setCode(200)->setBody([ |
||
384 | 'status' => 200, |
||
385 | 'data' => $result, |
||
386 | ]); |
||
387 | } |
||
388 | |||
389 | /** |
||
390 | * @api {post} /api/v1/user/quota?uid=:uid Set quota |
||
391 | * @apiVersion 1.0.0 |
||
392 | * @apiName postQuota |
||
393 | * @apiUse _getUser |
||
394 | * @apiGroup User |
||
395 | * @apiPermission admin |
||
396 | * @apiDescription Set quota for user |
||
397 | * |
||
398 | * @apiExample Example usage: |
||
399 | * curl -XPOST -d hard=10000000 -d soft=999999 "https://SERVER/api/v1/user/quota" |
||
400 | * curl -XPOST -d hard=10000000 -d soft=999999 "https://SERVER/api/v1/user/544627ed3c58891f058b4611/quota" |
||
401 | * curl -XPOST -d hard=10000000 -d soft=999999 "https://SERVER/api/v1/user/quota?uname=loginuser" |
||
402 | * |
||
403 | * @apiParam (GET Parameter) {number} hard The new hard quota in bytes |
||
404 | * @apiParam (GET Parameter) {number} soft The new soft quota in bytes |
||
405 | * |
||
406 | * @apiSuccessExample {json} Success-Response: |
||
407 | * HTTP/1.1 204 No Content |
||
408 | * |
||
409 | * @param string $uname |
||
410 | * @param string $uid |
||
411 | */ |
||
412 | public function postQuota(int $hard, int $soft, ?string $uid = null, ?string $uname = null): Response |
||
413 | { |
||
414 | $result = $this->_getUser($uid, $uname, true) |
||
0 ignored issues
–
show
The method
setHardQuota() does not seem to exist on object<Balloon\App\Api\v1\User> .
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed.
Loading history...
$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
Loading history...
|
|||
415 | ->setHardQuota($hard) |
||
416 | ->setSoftQuota($soft); |
||
417 | |||
418 | return (new Response())->setCode(204); |
||
419 | } |
||
420 | } |
||
421 |
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.
Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..