Skip to content

Commit

Permalink
#179 Endpoint for deleting users and user-folders (#118)
Browse files Browse the repository at this point in the history
* Initial delete user and folder.

* Apply php-cs-fixer changes

* Small restructuring.

* Add unit Tests.

* Apply php-cs-fixer changes

* Add line.

* Use HttpResponseCode

* Move IsGranted.

* Controller should have throw tag for Exceptions.

---------

Co-authored-by: martineiber <martineiber@users.noreply.github.com>
  • Loading branch information
martineiber and martineiber authored Jun 13, 2024
1 parent 65fdbaf commit c7fdeb7
Show file tree
Hide file tree
Showing 19 changed files with 818 additions and 2 deletions.
6 changes: 6 additions & 0 deletions config/users.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ services:
Pimcore\Bundle\StudioBackendBundle\User\Service\UserServiceInterface:
class: Pimcore\Bundle\StudioBackendBundle\User\Service\UserService

Pimcore\Bundle\StudioBackendBundle\User\Service\UserFolderServiceInterface:
class: Pimcore\Bundle\StudioBackendBundle\User\Service\UserFolderService

Pimcore\Bundle\StudioBackendBundle\User\Service\UserCloneServiceInterface:
class: Pimcore\Bundle\StudioBackendBundle\User\Service\UserCloneService

Expand All @@ -32,3 +35,6 @@ services:

Pimcore\Bundle\StudioBackendBundle\User\Repository\UserRepositoryInterface:
class: Pimcore\Bundle\StudioBackendBundle\User\Repository\UserRepository

Pimcore\Bundle\StudioBackendBundle\User\Repository\UserFolderRepositoryInterface:
class: Pimcore\Bundle\StudioBackendBundle\User\Repository\UserFolderRepository
30 changes: 30 additions & 0 deletions src/Exception/ForbiddenException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php
declare(strict_types=1);

/**
* Pimcore
*
* This source file is available under two different licenses:
* - GNU General Public License version 3 (GPLv3)
* - Pimcore Commercial License (PCL)
* Full copyright and license information is available in
* LICENSE.md which is distributed with this source code.
*
* @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org)
* @license http://www.pimcore.org/license GPLv3 and PCL
*/

namespace Pimcore\Bundle\StudioBackendBundle\Exception;

use Pimcore\Bundle\StudioBackendBundle\Util\Constants\HttpResponseCodes;

/**
* @internal
*/
final class ForbiddenException extends AbstractApiException
{
public function __construct(string $message = 'Access Denied')
{
parent::__construct(HttpResponseCodes::FORBIDDEN->value, $message);
}
}
8 changes: 8 additions & 0 deletions src/User/Controller/CloneController.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
use OpenApi\Attributes\JsonContent;
use OpenApi\Attributes\Post;
use Pimcore\Bundle\StudioBackendBundle\Controller\AbstractApiController;
use Pimcore\Bundle\StudioBackendBundle\Exception\DatabaseException;
use Pimcore\Bundle\StudioBackendBundle\Exception\NotFoundException;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Parameters\Path\IdParameter;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Request\SingleParameterRequestBody;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Response\DefaultResponses;
Expand All @@ -28,10 +30,12 @@
use Pimcore\Bundle\StudioBackendBundle\User\Schema\UserTreeNode;
use Pimcore\Bundle\StudioBackendBundle\User\Service\UserCloneServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\Util\Constants\HttpResponseCodes;
use Pimcore\Bundle\StudioBackendBundle\Util\Constants\UserPermissions;
use Pimcore\Bundle\StudioBackendBundle\Util\Traits\PaginatedResponseTrait;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpKernel\Attribute\MapRequestPayload;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
use Symfony\Component\Serializer\SerializerInterface;

/**
Expand All @@ -48,7 +52,11 @@ public function __construct(
}


/**
* @throws DatabaseException|NotFoundException
*/
#[Route('/user/clone/{id}', name: 'pimcore_studio_api_user_clone', methods: ['POST'])]
#[IsGranted(UserPermissions::USER_MANAGEMENT->value)]
#[Post(
path: self::API_PATH . '/user/clone/{id}',
operationId: 'cloneUser',
Expand Down
3 changes: 3 additions & 0 deletions src/User/Controller/CollectionController.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,12 @@
use Pimcore\Bundle\StudioBackendBundle\User\Schema\UserTreeNode;
use Pimcore\Bundle\StudioBackendBundle\User\Service\UserServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\Util\Constants\HttpResponseCodes;
use Pimcore\Bundle\StudioBackendBundle\Util\Constants\UserPermissions;
use Pimcore\Bundle\StudioBackendBundle\Util\Traits\PaginatedResponseTrait;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\MapQueryString;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
use Symfony\Component\Serializer\SerializerInterface;

/**
Expand All @@ -49,6 +51,7 @@ public function __construct(


#[Route('/users', name: 'pimcore_studio_api_users', methods: ['GET'])]
#[IsGranted(UserPermissions::USER_MANAGEMENT->value)]
#[Get(
path: self::API_PATH . '/users',
operationId: 'getUsers',
Expand Down
73 changes: 73 additions & 0 deletions src/User/Controller/DeleteUserController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?php
declare(strict_types=1);

/**
* Pimcore
*
* This source file is available under two different licenses:
* - GNU General Public License version 3 (GPLv3)
* - Pimcore Commercial License (PCL)
* Full copyright and license information is available in
* LICENSE.md which is distributed with this source code.
*
* @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org)
* @license http://www.pimcore.org/license GPLv3 and PCL
*/

namespace Pimcore\Bundle\StudioBackendBundle\User\Controller;

use OpenApi\Attributes\Delete;
use Pimcore\Bundle\StudioBackendBundle\Controller\AbstractApiController;
use Pimcore\Bundle\StudioBackendBundle\Exception\DatabaseException;
use Pimcore\Bundle\StudioBackendBundle\Exception\ForbiddenException;
use Pimcore\Bundle\StudioBackendBundle\Exception\NotFoundException;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Parameters\Path\IdParameter;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Response\DefaultResponses;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Response\SuccessResponse;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Config\Tags;
use Pimcore\Bundle\StudioBackendBundle\User\Service\UserServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\Util\Constants\HttpResponseCodes;
use Pimcore\Bundle\StudioBackendBundle\Util\Constants\UserPermissions;
use Pimcore\Bundle\StudioBackendBundle\Util\Traits\PaginatedResponseTrait;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
use Symfony\Component\Serializer\SerializerInterface;

/**
* @internal
*/
final class DeleteUserController extends AbstractApiController
{
use PaginatedResponseTrait;
public function __construct(
SerializerInterface $serializer,
private readonly UserServiceInterface $userService
) {
parent::__construct($serializer);
}


/**
* @throws NotFoundException|ForbiddenException|DatabaseException
*/
#[Route('/user/{id}', name: 'pimcore_studio_api_user_delete', methods: ['DELETE'])]
#[IsGranted(UserPermissions::USER_MANAGEMENT->value)]
#[Delete(
path: self::API_PATH . '/user/{id}',
operationId: 'deleteUser',
summary: 'Delete a specific user.',
tags: [Tags::User->value]
)]
#[SuccessResponse]
#[IdParameter(type: 'user')]
#[DefaultResponses([
HttpResponseCodes::NOT_FOUND,
HttpResponseCodes::FORBIDDEN,
])]
public function cloneUser(int $id): Response
{
$this->userService->deleteUser($id);
return new Response();
}
}
72 changes: 72 additions & 0 deletions src/User/Controller/DeleteUserFolderController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php
declare(strict_types=1);

/**
* Pimcore
*
* This source file is available under two different licenses:
* - GNU General Public License version 3 (GPLv3)
* - Pimcore Commercial License (PCL)
* Full copyright and license information is available in
* LICENSE.md which is distributed with this source code.
*
* @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org)
* @license http://www.pimcore.org/license GPLv3 and PCL
*/

namespace Pimcore\Bundle\StudioBackendBundle\User\Controller;

use OpenApi\Attributes\Delete;
use Pimcore\Bundle\StudioBackendBundle\Controller\AbstractApiController;
use Pimcore\Bundle\StudioBackendBundle\Exception\DatabaseException;
use Pimcore\Bundle\StudioBackendBundle\Exception\ForbiddenException;
use Pimcore\Bundle\StudioBackendBundle\Exception\NotFoundException;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Parameters\Path\IdParameter;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Response\DefaultResponses;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Response\SuccessResponse;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Config\Tags;
use Pimcore\Bundle\StudioBackendBundle\User\Service\UserFolderServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\Util\Constants\HttpResponseCodes;
use Pimcore\Bundle\StudioBackendBundle\Util\Constants\UserPermissions;
use Pimcore\Bundle\StudioBackendBundle\Util\Traits\PaginatedResponseTrait;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
use Symfony\Component\Serializer\SerializerInterface;

/**
* @internal
*/
final class DeleteUserFolderController extends AbstractApiController
{
use PaginatedResponseTrait;
public function __construct(
SerializerInterface $serializer,
private readonly UserFolderServiceInterface $userFolderService
) {
parent::__construct($serializer);
}


/**
* @throws ForbiddenException|NotFoundException|DatabaseException
*/
#[Route('/user/folder/{id}', name: 'pimcore_studio_api_user_folder_delete', methods: ['DELETE'])]
#[IsGranted(UserPermissions::PIMCORE_ADMIN->value)]
#[Delete(
path: self::API_PATH . '/user/folder/{id}',
operationId: 'deleteUserFolder',
summary: 'Delete a specific user folder with all users in this folder.',
tags: [Tags::User->value]
)]
#[SuccessResponse]
#[IdParameter(type: 'user-folder')]
#[DefaultResponses([
HttpResponseCodes::NOT_FOUND
])]
public function deleteUserFolder(int $id): Response
{
$this->userFolderService->deleteUserFolderById($id);
return new Response();
}
}
57 changes: 57 additions & 0 deletions src/User/Repository/UserFolderRepository.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php
declare(strict_types=1);

/**
* Pimcore
*
* This source file is available under two different licenses:
* - GNU General Public License version 3 (GPLv3)
* - Pimcore Commercial License (PCL)
* Full copyright and license information is available in
* LICENSE.md which is distributed with this source code.
*
* @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org)
* @license http://www.pimcore.org/license GPLv3 and PCL
*/

namespace Pimcore\Bundle\StudioBackendBundle\User\Repository;

use Exception;
use Pimcore\Bundle\StaticResolverBundle\Models\User\FolderResolverInterface;
use Pimcore\Bundle\StudioBackendBundle\Exception\NotFoundException;
use Pimcore\Model\User\Folder;

/**
* @internal
*/
final readonly class UserFolderRepository implements UserFolderRepositoryInterface
{

public function __construct(
private FolderResolverInterface $folderResolver
)
{
}

/**
* @throws Exception
*/
public function deleteUserFolder(Folder $folder): void
{
$folder->delete();
}

/**
* @throws NotFoundException
*/
public function getUserFolderById(int $folderId): Folder
{
$folder = $this->folderResolver->getById($folderId);

if (!$folder instanceof Folder) {
throw new NotFoundException(sprintf("User folder with ID %d not found", $folderId));
}

return $folder;
}
}
37 changes: 37 additions & 0 deletions src/User/Repository/UserFolderRepositoryInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php
declare(strict_types=1);

/**
* Pimcore
*
* This source file is available under two different licenses:
* - GNU General Public License version 3 (GPLv3)
* - Pimcore Commercial License (PCL)
* Full copyright and license information is available in
* LICENSE.md which is distributed with this source code.
*
* @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org)
* @license http://www.pimcore.org/license GPLv3 and PCL
*/

namespace Pimcore\Bundle\StudioBackendBundle\User\Repository;

use Exception;
use Pimcore\Bundle\StudioBackendBundle\Exception\NotFoundException;
use Pimcore\Model\User\Folder;

/**
* @internal
*/
interface UserFolderRepositoryInterface
{
/**
* @throws Exception
*/
public function deleteUserFolder(Folder $folder): void;

/**
* @throws NotFoundException
*/
public function getUserFolderById(int $folderId): Folder;
}
36 changes: 35 additions & 1 deletion src/User/Repository/UserRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,25 @@

namespace Pimcore\Bundle\StudioBackendBundle\User\Repository;

use Exception;
use Pimcore\Bundle\StaticResolverBundle\Models\User\UserResolverInterface;
use Pimcore\Bundle\StudioBackendBundle\Exception\NotFoundException;
use Pimcore\Model\User;
use Pimcore\Model\User\Listing as UserListing;
use Pimcore\Model\UserInterface;

/**
* @internal
*/
final class UserRepository implements UserRepositoryInterface
final readonly class UserRepository implements UserRepositoryInterface
{

public function __construct(
private UserResolverInterface $userResolver
)
{
}

public function getUserListingByParentId(int $parentId): UserListing
{
$listing = new UserListing();
Expand All @@ -33,4 +45,26 @@ public function getUserListingByParentId(int $parentId): UserListing

return $listing;
}

/**
* @throws NotFoundException
*/
public function getUserById(int $userId): UserInterface
{
$user = $this->userResolver->getById($userId);

if (!$user instanceof User) {
throw new NotFoundException(sprintf("User with ID %d not found", $userId));
}

return $user;
}

/**
* @throws Exception
*/
public function deleteUser(UserInterface $user): void
{
$user->delete();
}
}
Loading

0 comments on commit c7fdeb7

Please sign in to comment.