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(); |
||
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()) { |
||
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
|
|||
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); |
||
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(), |
||
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) |
||
415 | ->setHardQuota($hard) |
||
416 | ->setSoftQuota($soft); |
||
417 | |||
418 | return (new Response())->setCode(204); |
||
419 | } |
||
420 | } |
||
421 |
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:
Our function
my_function
expects aPost
object, and outputs the author of the post. The base classPost
returns a simple string and outputting a simple string will work just fine. However, the child classBlogPost
which is a sub-type ofPost
instead decided to return anobject
, and is therefore violating the SOLID principles. If aBlogPost
were passed tomy_function
, PHP would not complain, but ultimately fail when executing thestrtoupper
call in its body.