setCurrentUser($this->getUser()); $visible = $paramFetcher->get('visible'); if (\is_string($visible) && $visible !== '') { $query->setVisibility((int) $visible); } $order = $paramFetcher->get('order'); if (\is_string($order) && $order !== '') { $query->setOrder($order); } $orderBy = $paramFetcher->get('orderBy'); if (\is_string($orderBy) && $orderBy !== '') { $query->setOrderBy($orderBy); } $term = $paramFetcher->get('term'); if (\is_string($term) && $term !== '') { $query->setSearchTerm(new SearchTerm($term)); } $query->setIsApiCall(true); $data = $this->repository->getUsersForQuery($query); $view = new View($data, 200); $full = $paramFetcher->get('full'); if ($full === '1' || $full === 'true') { $view->getContext()->setGroups(self::GROUPS_COLLECTION_FULL); } else { $view->getContext()->setGroups(self::GROUPS_COLLECTION); } return $this->viewHandler->handle($view); } /** * Return one user entity */ #[IsGranted('view', 'profile')] #[OA\Response(response: 200, description: 'Return one user entity.', content: new OA\JsonContent(ref: '#/components/schemas/UserEntity'))] #[OA\Parameter(name: 'id', in: 'path', description: 'User ID to fetch', required: true)] #[Route(methods: ['GET'], path: '/{id}', name: 'get_user', requirements: ['id' => '\d+'])] public function getAction(User $profile, EventDispatcherInterface $dispatcher): Response { // we need to prepare the user preferences, which is done via an EventSubscriber $event = new PrepareUserEvent($profile); $dispatcher->dispatch($event); $view = new View($profile, 200); $view->getContext()->setGroups(self::GROUPS_ENTITY); return $this->viewHandler->handle($view); } /** * Return the current user entity */ #[OA\Response(response: 200, description: 'Return the current user entity.', content: new OA\JsonContent(ref: '#/components/schemas/UserEntity'))] #[Route(methods: ['GET'], path: '/me', name: 'me_user')] public function meAction(): Response { $view = new View($this->getUser(), 200); $view->getContext()->setGroups(self::GROUPS_ENTITY); return $this->viewHandler->handle($view); } /** * Creates a new user */ #[IsGranted('create_user')] #[OA\Post(description: 'Creates a new user and returns it afterwards')] #[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/UserCreateForm'))] #[Route(methods: ['POST'], path: '', name: 'post_user')] public function postAction(Request $request): Response { $user = new User(); $user->setEnabled(true); $user->setRoles([User::DEFAULT_ROLE]); $user->setTimezone($this->configuration->getUserDefaultTimezone()); $user->setLanguage($this->configuration->getUserDefaultLanguage()); $form = $this->createForm(UserApiCreateForm::class, $user, [ 'include_roles' => $this->isGranted('roles', $user), 'include_active_flag' => true, 'include_preferences' => true, ]); $form->submit($request->request->all()); if ($form->isValid()) { $plainPassword = $user->getPlainPassword(); if ($plainPassword === null) { throw new BadRequestHttpException('Password cannot be empty'); } $password = $this->passwordHasher->hashPassword($user, $plainPassword); $user->setPassword($password); if ($user->getPlainApiToken() !== null) { $user->setApiToken($this->passwordHasher->hashPassword($user, $user->getPlainApiToken())); } $this->repository->saveUser($user); $view = new View($user, 200); $view->getContext()->setGroups(self::GROUPS_ENTITY); $user->eraseCredentials(); return $this->viewHandler->handle($view); } $view = new View($form); $view->getContext()->setGroups(self::GROUPS_FORM); return $this->viewHandler->handle($view); } /** * Update an existing user */ #[IsGranted('edit', 'profile')] #[OA\Patch(description: 'Update an existing user, you can pass all or just a subset of all attributes (passing roles will replace all existing ones)', responses: [new OA\Response(response: 200, description: 'Returns the updated user', content: new OA\JsonContent(ref: '#/components/schemas/UserEntity'))])] #[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/UserEditForm'))] #[OA\Parameter(name: 'id', in: 'path', description: 'User ID to update', required: true)] #[Route(methods: ['PATCH'], path: '/{id}', name: 'patch_user', requirements: ['id' => '\d+'])] public function patchAction(Request $request, User $profile): Response { $form = $this->createForm(UserApiEditForm::class, $profile, [ 'include_roles' => $this->isGranted('roles', $profile), 'include_active_flag' => ($profile->getId() !== $this->getUser()->getId()), 'include_preferences' => $this->isGranted('preferences', $profile), 'include_supervisor' => $this->isGranted('supervisor', $profile), 'include_password_reset' => $this->isGranted('password', $profile), ]); $form->setData($profile); $form->submit($request->request->all(), false); if (false === $form->isValid()) { $view = new View($form, Response::HTTP_OK); $view->getContext()->setGroups(self::GROUPS_FORM); return $this->viewHandler->handle($view); } $this->repository->saveUser($profile); $view = new View($profile, Response::HTTP_OK); $view->getContext()->setGroups(self::GROUPS_ENTITY); return $this->viewHandler->handle($view); } /** * Delete an API token for the current user */ #[OA\Delete(responses: [new OA\Response(response: 200, description: 'Success if the token could be deleted.')])] #[OA\Parameter(name: 'id', in: 'path', description: 'The API token ID to remove', required: true)] #[Route(methods: ['DELETE'], path: '/api-token/{id}', name: 'delete_api_token', requirements: ['id' => '\d+'])] public function deleteApiToken(AccessToken $accessToken, AccessTokenRepository $accessTokenRepository): Response { $user = $this->getUser(); if (!$this->isGranted('api-token', $user)) { throw $this->createAccessDeniedException('User has no access to API tokens'); } if ($accessToken->getUser() !== $user) { throw $this->createAccessDeniedException('You are not allowed to delete this access token'); } $accessTokenRepository->deleteAccessToken($accessToken); $view = new View(null, Response::HTTP_OK); $view->getContext()->setGroups(self::GROUPS_ENTITY); return $this->viewHandler->handle($view); } }