Passed
Pull Request — master (#7302)
by Angel Fernando Quiroz
18:19 queued 07:15
created

UserCollectionController::listUsers()   A

Complexity

Conditions 5
Paths 8

Size

Total Lines 44
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 28
c 1
b 0
f 0
nc 8
nop 1
dl 0
loc 44
rs 9.1608
1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
declare(strict_types=1);
6
7
namespace Chamilo\CoreBundle\Controller\Scim;
8
9
use Chamilo\CoreBundle\Entity\User;
10
use Chamilo\CoreBundle\Entity\UserAuthSource;
11
use Chamilo\CoreBundle\Exception\ScimException;
12
use Chamilo\CoreBundle\Helpers\AccessUrlHelper;
13
use Chamilo\CoreBundle\Helpers\ScimHelper;
14
use Chamilo\CoreBundle\Repository\Node\UserRepository;
15
use Chamilo\CoreBundle\Serializer\Denormalizer\Scim\UserDenormalizer;
16
use Chamilo\CoreBundle\Serializer\Normalizer\Scim\UserNormalizer;
17
use Doctrine\ORM\EntityManagerInterface;
18
use Doctrine\ORM\NonUniqueResultException;
19
use Doctrine\ORM\NoResultException;
20
use Symfony\Component\HttpFoundation\JsonResponse;
21
use Symfony\Component\HttpFoundation\Request;
22
use Symfony\Component\HttpFoundation\Response;
23
use Symfony\Component\HttpKernel\Exception\ConflictHttpException;
24
use Symfony\Component\Routing\Attribute\Route;
25
use Symfony\Component\Serializer\SerializerInterface;
26
use Symfony\Contracts\Translation\TranslatorInterface;
27
28
#[Route('/scim/v2/Users', name: 'scim_users')]
29
class UserCollectionController extends AbstractScimController
30
{
31
    public function __construct(
32
        private readonly UserRepository $userRepository,
33
        private readonly SerializerInterface $serializer,
34
        private readonly AccessUrlHelper $accessUrlHelper,
35
        private readonly EntityManagerInterface $entityManager,
36
        private readonly TranslatorInterface $translator,
37
        private readonly ScimHelper $scimHelper,
38
    ) {}
39
40
    #[Route('', methods: ['GET'])]
41
    public function listUsers(Request $request): JsonResponse
42
    {
43
        $startIndex = max(1, $request->query->getInt('startIndex', 1));
44
        $count = min(100, $request->query->getInt('count', 30));
45
        $filter = $request->query->get('filter');
46
47
        $qb = $this->userRepository->createQueryBuilder('u');
48
49
        if ($filter && preg_match('/userName\s+eq\s+"([^"]+)"/i', $filter, $matches)) {
50
            $qb
51
                ->andWhere('u.username = :username')
52
                ->setParameter('username', $matches[1])
53
            ;
54
        }
55
56
        try {
57
            $total = (clone $qb)->select('COUNT(u.id)')->getQuery()->getSingleScalarResult();
58
        } catch (NonUniqueResultException|NoResultException) {
59
            $total = 0;
60
        }
61
62
        $users = $qb
63
            ->setFirstResult($startIndex - 1)
64
            ->setMaxResults($count)
65
            ->getQuery()
66
            ->getResult()
67
        ;
68
69
        $resources = [];
70
71
        foreach ($users as $user) {
72
            $resources[] = $this->serializer->normalize($user, UserNormalizer::FORMAT);
73
        }
74
75
        $response = [
76
            'schemas' => ['urn:ietf:params:scim:api:messages:2.0:ListResponse'],
77
            'totalResults' => (int) $total,
78
            'itemsPerPage' => \count($resources),
79
            'startIndex' => $startIndex,
80
            'Resources' => $resources,
81
        ];
82
83
        return new JsonResponse($response, Response::HTTP_OK, ['Content-Type' => self::SCIM_CONTENT_TYPE]);
84
    }
85
86
    #[Route('', methods: ['POST'])]
87
    public function createUser(Request $request): JsonResponse
88
    {
89
        $data = $this->getAndValidateJson($request);
90
91
        /** @var User $user */
92
        $user = $this->serializer->denormalize($data, User::class, UserDenormalizer::FORMAT);
93
94
        if ($this->userRepository->findOneBy(['username' => $user->getUsername()])) {
95
            throw new ConflictHttpException($this->translator->trans('This login is already in use'));
96
        }
97
98
        $currentAccessUrl = $this->accessUrlHelper->getCurrent();
99
100
        $user
101
            ->setCreator($this->userRepository->findOnePlatformAdmin())
102
            ->addAuthSourceByAuthentication(UserAuthSource::SCIM, $currentAccessUrl)
103
            ->setPlainPassword('scim')
104
            ->setStatus(STUDENT)
105
            ->setRoleFromStatus(STUDENT)
106
        ;
107
108
        $this->userRepository->updateUser($user);
109
110
        $currentAccessUrl->addUser($user);
111
112
        $this->entityManager->flush();
113
114
        if (isset($data['externalId'])) {
115
            $this->scimHelper->saveExternalId($data['externalId'], $user);
116
        }
117
118
        $normalized = $this->serializer->normalize($user, UserNormalizer::FORMAT);
119
120
        return new JsonResponse(
121
            $normalized,
122
            Response::HTTP_CREATED,
123
            [
124
                'Content-Type' => self::SCIM_CONTENT_TYPE,
125
                'Location' => $normalized['meta']['location'],
126
            ]
127
        );
128
    }
129
}
130