Skip to content

Commit

Permalink
[WIP][Feature] Notes & Events (#68)
Browse files Browse the repository at this point in the history
* Add note controllers, service, hydrator, repo, etc.

* Apply php-cs-fixer changes

* Add responses and new way for default responses

* Apply php-cs-fixer changes

* Add user permission guard

* Add delete controller and service methods, update descriptions of property controllers

* Add method to interface

* cleanup

* Add feedback from sonar

* Add more feedback

* Add collection route to list notes in general, separation between notes and element notes

* Adding json filter

* Apply php-cs-fixer changes

* Empty is enough

* Apply sonar cloud feedback

* Remove trailing spaces

* Add filterservice test

* Apply php-cs-fixer changes

* Add sort parameters

* Apply php-cs-fixer changes

* Add space

---------

Co-authored-by: mattamon <[email protected]>
  • Loading branch information
mattamon and mattamon authored May 23, 2024
1 parent a7297a1 commit 300dbd2
Show file tree
Hide file tree
Showing 42 changed files with 2,052 additions and 11 deletions.
28 changes: 28 additions & 0 deletions config/notes.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
services:
_defaults:
autowire: true
autoconfigure: true
public: false

# controllers are imported separately to make sure they're public
# and have a tag that allows actions to type-hint services
Pimcore\Bundle\StudioBackendBundle\Note\Controller\:
resource: '../src/Note/Controller'
public: true
tags: [ 'controller.service_arguments' ]

# Hydrators
Pimcore\Bundle\StudioBackendBundle\Note\Hydrator\NoteHydratorInterface:
class: Pimcore\Bundle\StudioBackendBundle\Note\Hydrator\NoteHydrator

Pimcore\Bundle\StudioBackendBundle\Note\Extractor\NoteDataExtractorInterface:
class: Pimcore\Bundle\StudioBackendBundle\Note\Extractor\NoteDataExtractor

Pimcore\Bundle\StudioBackendBundle\Note\Repository\NoteRepositoryInterface:
class: Pimcore\Bundle\StudioBackendBundle\Note\Repository\NoteRepository

Pimcore\Bundle\StudioBackendBundle\Note\Service\NoteServiceInterface:
class: Pimcore\Bundle\StudioBackendBundle\Note\Service\NoteService

Pimcore\Bundle\StudioBackendBundle\Note\Service\FilterServiceInterface:
class: Pimcore\Bundle\StudioBackendBundle\Note\Service\FilterService
1 change: 1 addition & 0 deletions src/DependencyInjection/PimcoreStudioBackendExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ public function load(array $configs, ContainerBuilder $container): void
$loader->load('factories.yaml');
$loader->load('filters.yaml');
$loader->load('icon.yaml');
$loader->load('notes.yaml');
$loader->load('open_api.yaml');
$loader->load('properties.yaml');
$loader->load('security.yaml');
Expand Down
4 changes: 2 additions & 2 deletions src/Exception/ElementNotFoundException.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
*/
final class ElementNotFoundException extends AbstractApiException
{
public function __construct(int $id)
public function __construct(int $id, string $type = 'Element')
{
parent::__construct(404, 'Element with ID ' . $id . ' not found');
parent::__construct(404, sprintf('%s with ID %d not found', $type, $id));
}
}
31 changes: 31 additions & 0 deletions src/Exception/InvalidFilterException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?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;

/**
* @internal
*/
final class InvalidFilterException extends AbstractApiException
{
public function __construct(string $filter)
{
parent::__construct(
400,
sprintf('Invalid filter: %s', $filter)
);
}
}
50 changes: 50 additions & 0 deletions src/Note/Attributes/Parameters/Query/NoteSortByParameter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?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\Note\Attributes\Parameters\Query;

use Attribute;
use OpenApi\Attributes\QueryParameter;
use OpenApi\Attributes\Schema;

#[Attribute(Attribute::TARGET_METHOD)]
final class NoteSortByParameter extends QueryParameter
{
public function __construct()
{
parent::__construct(
name: 'sortBy',
description: 'Sort by field. Only works in combination with sortOrder.',
in: 'query',
required: false,
schema: new Schema(
type: 'string',
enum: [
'id',
'type',
'cId',
'cType',
'cPath',
'date',
'title',
'description',
'locked',
],
example: null,
),
);
}
}
34 changes: 34 additions & 0 deletions src/Note/Attributes/Request/CreateNoteRequestBody.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?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\Note\Attributes\Request;

use Attribute;
use OpenApi\Attributes\JsonContent;
use OpenApi\Attributes\RequestBody;
use Pimcore\Bundle\StudioBackendBundle\Note\Schema\CreateNote;

#[Attribute(Attribute::TARGET_METHOD)]
final class CreateNoteRequestBody extends RequestBody
{
public function __construct()
{
parent::__construct(
required: true,
content: new JsonContent(ref: CreateNote::class)
);
}
}
37 changes: 37 additions & 0 deletions src/Note/Attributes/Response/Property/NoteCollection.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\Note\Attributes\Response\Property;

use OpenApi\Attributes\Items;
use OpenApi\Attributes\Property;
use Pimcore\Bundle\StudioBackendBundle\Note\Schema\Note;

/**
* @internal
*/
final class NoteCollection extends Property
{
public function __construct()
{
parent::__construct(
'items',
title: 'items',
type: 'array',
items: new Items(ref: Note::class)
);
}
}
93 changes: 93 additions & 0 deletions src/Note/Controller/CollectionController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<?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\Note\Controller;

use OpenApi\Attributes\Get;
use Pimcore\Bundle\StudioBackendBundle\Controller\AbstractApiController;
use Pimcore\Bundle\StudioBackendBundle\Note\Attributes\Parameters\Query\NoteSortByParameter;
use Pimcore\Bundle\StudioBackendBundle\Note\Attributes\Response\Property\NoteCollection;
use Pimcore\Bundle\StudioBackendBundle\Note\Request\NoteElement;
use Pimcore\Bundle\StudioBackendBundle\Note\Request\NoteParameters;
use Pimcore\Bundle\StudioBackendBundle\Note\Service\NoteServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Parameters\Query\FieldFilterParameter;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Parameters\Query\FilterParameter;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Parameters\Query\PageParameter;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Parameters\Query\PageSizeParameter;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Parameters\Query\SortOrderParameter;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Response\Content\CollectionJson;
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\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\MapQueryString;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
use Symfony\Component\Serializer\SerializerInterface;

/**
* @internal
*/
final class CollectionController extends AbstractApiController
{
use PaginatedResponseTrait;

public function __construct(
SerializerInterface $serializer,
private readonly NoteServiceInterface $noteService
)
{
parent::__construct($serializer);
}

#[Route('/notes', name: 'pimcore_studio_api_get_notes', methods: ['GET'])]
#[IsGranted(UserPermissions::NOTES_EVENTS->value)]
#[Get(
path: self::API_PATH . '/notes',
operationId: 'getNotes',
summary: 'Get notes',
security: self::SECURITY_SCHEME,
tags: [Tags::Notes->name]
)]
#[PageParameter]
#[PageSizeParameter(50)]
#[NoteSortByParameter]
#[SortOrderParameter]
#[FilterParameter('notes')]
#[FieldFilterParameter]
#[SuccessResponse(
description: 'Paginated assets with total count as header param',
content: new CollectionJson(new NoteCollection())
)]
#[DefaultResponses([
HttpResponseCodes::UNAUTHORIZED
])]
public function getNotes(
#[MapQueryString] NoteParameters $parameters = new NoteParameters()
): JsonResponse
{
$collection = $this->noteService->listNotes(new NoteElement(), $parameters);

return $this->getPaginatedCollection(
$this->serializer,
$collection->getItems(),
$collection->getTotalItems()
);
}
}
74 changes: 74 additions & 0 deletions src/Note/Controller/DeleteController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<?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\Note\Controller;

use OpenApi\Attributes\Delete;
use Pimcore\Bundle\StudioBackendBundle\Controller\AbstractApiController;
use Pimcore\Bundle\StudioBackendBundle\Exception\ElementNotFoundException;
use Pimcore\Bundle\StudioBackendBundle\Note\Service\NoteServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Parameters\Path\IdParameter;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Response\Content\IdJson;
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\Util\Constants\HttpResponseCodes;
use Pimcore\Bundle\StudioBackendBundle\Util\Constants\UserPermissions;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
use Symfony\Component\Serializer\SerializerInterface;

/**
* @internal
*/
final class DeleteController extends AbstractApiController
{
public function __construct(
SerializerInterface $serializer,
private readonly NoteServiceInterface $noteService
)
{
parent::__construct($serializer);
}

/**
* @throws ElementNotFoundException
*/
#[Route('/notes/{id}', name: 'pimcore_studio_api_delete_note', methods: ['DELETE'])]
#[IsGranted(UserPermissions::NOTES_EVENTS->value)]
#[Delete(
path: self::API_PATH . '/notes/{id}',
operationId: 'deleteNote',
summary: 'Deleting note by id',
security: self::SECURITY_SCHEME,
tags: [Tags::Notes->name]
)]
#[IdParameter]
#[SuccessResponse(
description: 'Id of the note that got deleted',
content: new IdJson('ID of deleted note')
)]
#[DefaultResponses([
HttpResponseCodes::NOT_FOUND,
HttpResponseCodes::UNAUTHORIZED
])]
public function deleteNote(int $id): JsonResponse
{
$this->noteService->deleteNote($id);
return $this->jsonResponse(['id' => $id]);
}
}
Loading

0 comments on commit 300dbd2

Please sign in to comment.