Passed
Branch master (933aa9)
by Tarmo
06:57
created

UserController::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 2
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
declare(strict_types = 1);
3
/**
4
 * /src/Controller/UserController.php
5
 *
6
 * @author  TLe, Tarmo Leppänen <[email protected]>
7
 */
8
namespace App\Controller;
9
10
use App\Annotation\RestApiDoc;
11
use App\Entity\User;
12
use App\Entity\UserGroup;
13
use App\Form\Type\Rest\User\UserCreateType;
14
use App\Form\Type\Rest\User\UserPatchType;
15
use App\Form\Type\Rest\User\UserUpdateType;
16
use App\Resource\UserResource;
17
use App\Rest\Controller;
18
use App\Rest\ResponseHandler;
19
use App\Rest\Traits\Actions;
20
use App\Rest\Traits\Methods;
21
use App\Security\RolesService;
22
use Nelmio\ApiDocBundle\Annotation\Model;
23
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
24
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
25
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
26
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
27
use Swagger\Annotations as SWG;
28
use Symfony\Component\HttpFoundation\JsonResponse;
29
use Symfony\Component\HttpFoundation\Request;
30
use Symfony\Component\HttpFoundation\Response;
31
use Symfony\Component\HttpKernel\Exception\HttpException;
32
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
33
use Symfony\Component\Serializer\SerializerInterface;
34
35
/** @noinspection PhpHierarchyChecksInspection */
36
/** @noinspection PhpMissingParentCallCommonInspection */
37
/**
38
 * Class UserController
39
 *
40
 * @Route(path="/user")
41
 *
42
 * @Security("is_granted('IS_AUTHENTICATED_FULLY')")
43
 *
44
 * @SWG\Tag(name="User Management")
45
 *
46
 * @package App\Controller
47
 * @author  TLe, Tarmo Leppänen <[email protected]>
48
 *
49
 * @method UserResource getResource()
50
 */
51
class UserController extends Controller
52
{
53
    // Traits for REST actions
54
    use Actions\Admin\CountAction;
55
    use Actions\Admin\FindAction;
56
    use Actions\Admin\FindOneAction;
57
    use Actions\Admin\IdsAction;
58
    use Actions\Root\CreateAction;
59
    use Actions\Root\PatchAction;
60
    use Actions\Root\UpdateAction;
61
    use Methods\DeleteMethod;
62
    /**
63
     * Method + Form type class names (key + value)
64
     *
65
     * @var string[]
66
     */
67
    protected static $formTypes = [
68
        Controller::METHOD_PATCH => UserPatchType::class,
69
        Controller::METHOD_CREATE => UserCreateType::class,
70
        Controller::METHOD_UPDATE => UserUpdateType::class,
71
    ];
72
73
    /**
74
     * UserController constructor.
75
     *
76
     * @param UserResource    $resource
77
     * @param ResponseHandler $responseHandler
78
     */
79 94
    public function __construct(UserResource $resource, ResponseHandler $responseHandler)
80
    {
81 94
        $this->init($resource, $responseHandler);
82 94
    }
83
84
    /**
85
     * @Route(
86
     *      "/{requestUser}",
87
     *      requirements={
88
     *          "requestUser" = "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"
89
     *      }
90
     *  )
91
     *
92
     * @ParamConverter(
93
     *     "requestUser",
94
     *     class="App\Resource\UserResource"
95
     *  )
96
     *
97
     * @Method({"DELETE"})
98
     *
99
     * @Security("has_role('ROLE_ROOT')")
100
     *
101
     * @RestApiDoc()
102
     *
103
     * @param Request               $request
104
     * @param User                  $requestUser
105
     * @param TokenStorageInterface $tokenStorage
106
     *
107
     * @return Response
108
     *
109
     * @throws \LogicException
110
     * @throws \Symfony\Component\HttpKernel\Exception\HttpException
111
     * @throws \Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException
112
     */
113 2
    public function deleteAction(Request $request, User $requestUser, TokenStorageInterface $tokenStorage): Response
114
    {
115
        /** @noinspection NullPointerExceptionInspection */
116 2
        $currentUser = $tokenStorage->getToken()->getUser();
117
118 2
        if ($currentUser === $requestUser) {
119 1
            throw new HttpException(400, 'You cannot remove yourself...');
120
        }
121
122 1
        return $this->deleteMethod($request, $requestUser->getId());
123
    }
124
125
    /**
126
     * Endpoint action to fetch specified user roles.
127
     *
128
     * @Route(
129
     *      "/{requestUser}/roles",
130
     *      requirements={
131
     *          "requestUser" = "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"
132
     *      }
133
     *  )
134
     *
135
     * @ParamConverter(
136
     *     "requestUser",
137
     *     class="App\Resource\UserResource"
138
     *  )
139
     *
140
     * @Method({"GET"})
141
     *
142
     * @Security("is_granted('IS_USER_HIMSELF', requestUser) or has_role('ROLE_ROOT')")
143
     *
144
     * @SWG\Parameter(
145
     *      type="string",
146
     *      name="Authorization",
147
     *      in="header",
148
     *      required=true,
149
     *      description="Authorization header",
150
     *      default="Bearer _your_jwt_here_",
151
     *  )
152
     * @SWG\Response(
153
     *      response=200,
154
     *      description="Specified user roles",
155
     *      @SWG\Schema(
156
     *          type="array",
157
     *          @SWG\Items(type="string"),
158
     *      ),
159
     *  )
160
     * @SWG\Response(
161
     *      response=401,
162
     *      description="Unauthorized",
163
     *      examples={
164
     *          "Token not found": "{code: 401, message: 'JWT Token not found'}",
165
     *          "Expired token": "{code: 401, message: 'Expired JWT Token'}",
166
     *      },
167
     *      @SWG\Schema(
168
     *          type="object",
169
     *          @SWG\Property(property="code", type="integer", description="Error code"),
170
     *          @SWG\Property(property="message", type="string", description="Error description"),
171
     *      ),
172
     *  )
173
     * @SWG\Response(
174
     *      response=403,
175
     *      description="Access denied",
176
     *      examples={
177
     *          "Access denied": "{code: 403, message: 'Access denied'}",
178
     *      },
179
     *      @SWG\Schema(
180
     *          type="object",
181
     *          @SWG\Property(property="code", type="integer", description="Error code"),
182
     *          @SWG\Property(property="message", type="string", description="Error description"),
183
     *      ),
184
     *  )
185
     * @SWG\Tag(name="User Management")
186
     *
187
     * @param User         $requestUser
188
     * @param RolesService $roles
189
     *
190
     * @return JsonResponse
191
     */
192 12
    public function getUserRolesAction(User $requestUser, RolesService $roles): JsonResponse
193
    {
194 12
        return new JsonResponse($roles->getInheritedRoles($requestUser->getRoles()));
195
    }
196
197
    /**
198
     * Endpoint action to fetch specified user user groups.
199
     *
200
     * @Route(
201
     *      "/{requestUser}/groups",
202
     *      requirements={
203
     *          "requestUser" = "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"
204
     *      }
205
     *  )
206
     *
207
     * @ParamConverter(
208
     *     "requestUser",
209
     *     class="App\Resource\UserResource"
210
     *  )
211
     *
212
     * @Method({"GET"})
213
     *
214
     * @Security("is_granted('IS_USER_HIMSELF', requestUser) or has_role('ROLE_ROOT')")
215
     *
216
     * @SWG\Parameter(
217
     *      type="string",
218
     *      name="Authorization",
219
     *      in="header",
220
     *      required=true,
221
     *      description="Authorization header",
222
     *      default="Bearer _your_jwt_here_",
223
     *  )
224
     * @SWG\Response(
225
     *      response=200,
226
     *      description="User groups",
227
     *      @SWG\Schema(
228
     *          type="array",
229
     *          @Model(
230
     *              type=App\Entity\UserGroup::class,
231
     *              groups={"UserGroup", "UserGroup.role"},
232
     *          ),
233
     *      ),
234
     *  )
235
     * @SWG\Response(
236
     *      response=401,
237
     *      description="Unauthorized",
238
     *      examples={
239
     *          "Token not found": "{code: 401, message: 'JWT Token not found'}",
240
     *          "Expired token": "{code: 401, message: 'Expired JWT Token'}",
241
     *      },
242
     *      @SWG\Schema(
243
     *          type="object",
244
     *          @SWG\Property(property="code", type="integer", description="Error code"),
245
     *          @SWG\Property(property="message", type="string", description="Error description"),
246
     *      ),
247
     *  )
248
     * @SWG\Response(
249
     *      response=403,
250
     *      description="Access denied",
251
     *      examples={
252
     *          "Access denied": "{code: 403, message: 'Access denied'}",
253
     *      },
254
     *      @SWG\Schema(
255
     *          type="object",
256
     *          @SWG\Property(property="code", type="integer", description="Error code"),
257
     *          @SWG\Property(property="message", type="string", description="Error description"),
258
     *      ),
259
     *  )
260
     * @SWG\Tag(name="User Management")
261
     *
262
     * @param User                $requestUser
263
     * @param SerializerInterface $serializer
264
     *
265
     * @return JsonResponse
266
     */
267 12
    public function getUserGroupsAction(User $requestUser, SerializerInterface $serializer): JsonResponse
268
    {
269 12
        return $this->getUserGroupResponse($requestUser, $serializer);
270
    }
271
272
    /**
273
     * Endpoint action to attach specified user group to specified user.
274
     *
275
     * @Route(
276
     *      "/{user}/group/{userGroup}",
277
     *      requirements={
278
     *          "user" = "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$",
279
     *          "userGroup" = "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$",
280
     *      }
281
     *  )
282
     *
283
     * @ParamConverter(
284
     *      "user",
285
     *      class="App\Resource\UserResource",
286
     *  )
287
     * @ParamConverter(
288
     *      "userGroup",
289
     *      class="App\Resource\UserGroupResource",
290
     *  )
291
     *
292
     * @Method({"POST"})
293
     *
294
     * @Security("has_role('ROLE_ROOT')")
295
     *
296
     * @SWG\Parameter(
297
     *      type="string",
298
     *      name="Authorization",
299
     *      in="header",
300
     *      required=true,
301
     *      description="Authorization header",
302
     *      default="Bearer _your_jwt_here_",
303
     *  )
304
     * @SWG\Parameter(
305
     *      type="string",
306
     *      name="userId",
307
     *      in="path",
308
     *      required=true,
309
     *      description="User GUID",
310
     *      default="User GUID",
311
     *  )
312
     * @SWG\Parameter(
313
     *      type="string",
314
     *      name="userGroupId",
315
     *      in="path",
316
     *      required=true,
317
     *      description="User Group GUID",
318
     *      default="User Group GUID",
319
     *  )
320
     * @SWG\Response(
321
     *      response=200,
322
     *      description="User groups (user already belongs to this group)",
323
     *      @SWG\Schema(
324
     *          type="array",
325
     *          @Model(
326
     *              type=App\Entity\UserGroup::class,
327
     *              groups={"UserGroup", "UserGroup.role"},
328
     *          ),
329
     *      ),
330
     *  )
331
     * @SWG\Response(
332
     *      response=201,
333
     *      description="User groups (user added to this group)",
334
     *      @SWG\Schema(
335
     *          type="array",
336
     *          @Model(
337
     *              type=App\Entity\UserGroup::class,
338
     *              groups={"UserGroup", "UserGroup.role"},
339
     *          ),
340
     *      ),
341
     *  )
342
     * @SWG\Response(
343
     *      response=401,
344
     *      description="Unauthorized",
345
     *      examples={
346
     *          "Token not found": "{code: 401, message: 'JWT Token not found'}",
347
     *          "Expired token": "{code: 401, message: 'Expired JWT Token'}",
348
     *      },
349
     *      @SWG\Schema(
350
     *          type="object",
351
     *          @SWG\Property(property="code", type="integer", description="Error code"),
352
     *          @SWG\Property(property="message", type="string", description="Error description"),
353
     *      ),
354
     *  )
355
     * @SWG\Response(
356
     *      response=403,
357
     *      description="Access denied",
358
     *      examples={
359
     *          "Access denied": "{code: 403, message: 'Access denied'}",
360
     *      },
361
     *      @SWG\Schema(
362
     *          type="object",
363
     *          @SWG\Property(property="code", type="integer", description="Error code"),
364
     *          @SWG\Property(property="message", type="string", description="Error description"),
365
     *      ),
366
     *  )
367
     * @SWG\Tag(name="User Management")
368
     *
369
     * @param User                $user
370
     * @param UserGroup           $userGroup
371
     * @param SerializerInterface $serializer
372
     *
373
     * @return JsonResponse
374
     */
375 2
    public function attachUserGroupAction(
376
        User $user,
377
        UserGroup $userGroup,
378
        SerializerInterface $serializer
379
    ): JsonResponse {
380 2
        $status = $user->getUserGroups()->contains($userGroup) ? 200 : 201;
381
382 2
        $this->getResource()->save($user->addUserGroup($userGroup));
383
384 2
        return $this->getUserGroupResponse($user, $serializer, $status);
385
    }
386
387
    /**
388
     * Endpoint action to detach specified user group from specified user.
389
     *
390
     * @Route(
391
     *      "/{user}/group/{userGroup}",
392
     *      requirements={
393
     *          "user" = "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$",
394
     *          "userGroup" = "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$",
395
     *      }
396
     *  )
397
     *
398
     * @ParamConverter(
399
     *      "user",
400
     *      class="App\Resource\UserResource",
401
     *  )
402
     * @ParamConverter(
403
     *      "userGroup",
404
     *      class="App\Resource\UserGroupResource",
405
     *  )
406
     *
407
     * @Method({"DELETE"})
408
     *
409
     * @Security("has_role('ROLE_ROOT')")
410
     *
411
     * @SWG\Parameter(
412
     *      type="string",
413
     *      name="Authorization",
414
     *      in="header",
415
     *      required=true,
416
     *      description="Authorization header",
417
     *      default="Bearer _your_jwt_here_",
418
     *  )
419
     * @SWG\Parameter(
420
     *      type="string",
421
     *      name="userId",
422
     *      in="path",
423
     *      required=true,
424
     *      description="User GUID",
425
     *      default="User GUID",
426
     *  )
427
     * @SWG\Parameter(
428
     *      type="string",
429
     *      name="userGroupId",
430
     *      in="path",
431
     *      required=true,
432
     *      description="User Group GUID",
433
     *      default="User Group GUID",
434
     *  )
435
     * @SWG\Response(
436
     *      response=200,
437
     *      description="User groups",
438
     *      @SWG\Schema(
439
     *          type="array",
440
     *          @Model(
441
     *              type=App\Entity\UserGroup::class,
442
     *              groups={"UserGroup", "UserGroup.role"},
443
     *          ),
444
     *      ),
445
     *  )
446
     * @SWG\Response(
447
     *      response=401,
448
     *      description="Unauthorized",
449
     *      examples={
450
     *          "Token not found": "{code: 401, message: 'JWT Token not found'}",
451
     *          "Expired token": "{code: 401, message: 'Expired JWT Token'}",
452
     *      },
453
     *      @SWG\Schema(
454
     *          type="object",
455
     *          @SWG\Property(property="code", type="integer", description="Error code"),
456
     *          @SWG\Property(property="message", type="string", description="Error description"),
457
     *      ),
458
     *  )
459
     * @SWG\Response(
460
     *      response=403,
461
     *      description="Forbidden",
462
     *      examples={
463
     *          "Access denied": "{code: 403, message: 'Access denied'}",
464
     *      },
465
     *      @SWG\Schema(
466
     *          type="object",
467
     *          @SWG\Property(property="code", type="integer", description="Error code"),
468
     *          @SWG\Property(property="message", type="string", description="Error description"),
469
     *      ),
470
     *  )
471
     * @SWG\Tag(name="User Management")
472
     *
473
     * @param User                $user
474
     * @param UserGroup           $userGroup
475
     * @param SerializerInterface $serializer
476
     *
477
     * @return JsonResponse
478
     */
479 1
    public function detachUserGroupAction(
480
        User $user,
481
        UserGroup $userGroup,
482
        SerializerInterface $serializer
483
    ): JsonResponse {
484 1
        $this->getResource()->save($user->removeUserGroup($userGroup));
485
486 1
        return $this->getUserGroupResponse($user, $serializer);
487
    }
488
489
    /**
490
     * Helper method to create UserGroup response.
491
     *
492
     * @param User                $user
493
     * @param SerializerInterface $serializer
494
     * @param int|null            $status
495
     *
496
     * @return JsonResponse
497
     */
498 15
    private function getUserGroupResponse(
499
        User $user,
500
        SerializerInterface $serializer,
501
        ?int $status = null
502
    ): JsonResponse {
503 15
        $status = $status ?? 200;
504
505 15
        static $groups = [
506
            'groups' => [
507
                'UserGroup',
508
                'UserGroup.role',
509
            ],
510
        ];
511
512 15
        return new JsonResponse(
513 15
            $serializer->serialize($user->getUserGroups()->getValues(), 'json', $groups),
514 15
            $status,
515 15
            [],
516 15
            true
517
        );
518
    }
519
}
520