Skip to content
Open

Dev #165

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions .coderabbit.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,11 @@ reviews:
high_level_summary_in_walkthrough: false
changed_files_summary: false
poem: false
finishing_touches:
docstrings:
enabled: false
auto_review:
enabled: true
base_branches:
- ".*"
drafts: false

checks:
docstring_coverage:
enabled: false
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,11 @@ contribute and how to run the unit tests and style checks locally.
This project adheres to a [Contributor Code of Conduct](CODE_OF_CONDUCT.md).
By participating in this project and its community, you are expected to uphold
this code.


### Code style checks
```bash
vendor/bin/phpstan analyse -l 5 src/ tests/
vendor/bin/phpmd src/ text vendor/phplist/core/config/PHPMD/rules.xml
vendor/bin/phpcs --standard=vendor/phplist/core/config/PhpCodeSniffer/ src/ tests/
```
9 changes: 6 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,20 @@
},
"require": {
"php": "^8.1",
"phplist/core": "dev-main",
"phplist/core": "dev-dev",
"friendsofsymfony/rest-bundle": "*",
"symfony/test-pack": "^1.0",
"symfony/process": "^6.4",
"zircote/swagger-php": "^4.11",
"ext-dom": "*",
"tatevikgr/rss-feed": "dev-main as 0.1.0"
"tatevikgr/rss-feed": "dev-main as 0.1.0",
"psr/simple-cache": "^3.0",
"symfony/expression-language": "^6.4",
"nelmio/cors-bundle": "^2.4"
},
"require-dev": {
"phpunit/phpunit": "^10.0",
"guzzlehttp/guzzle": "^6.3.0",
"guzzlehttp/guzzle": "^7.2.0",
"squizlabs/php_codesniffer": "^3.2.0",
"phpstan/phpstan": "^1.10",
"nette/caching": "^3.0.0",
Expand Down
100 changes: 6 additions & 94 deletions config/services/normalizers.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,104 +4,16 @@ services:
autoconfigure: true
public: false

_instanceof:
Symfony\Component\Serializer\Normalizer\NormalizerInterface:
tags: [ 'serializer.normalizer' ]

Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter: ~

Symfony\Component\Serializer\Normalizer\ObjectNormalizer:
arguments:
$classMetadataFactory: '@?serializer.mapping.class_metadata_factory'
$nameConverter: '@Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter'

PhpList\RestBundle\Subscription\Serializer\SubscriberNormalizer:
tags: [ 'serializer.normalizer' ]
autowire: true

PhpList\RestBundle\Subscription\Serializer\SubscriberOnlyNormalizer:
tags: [ 'serializer.normalizer' ]
autowire: true

PhpList\RestBundle\Identity\Serializer\AdministratorTokenNormalizer:
tags: [ 'serializer.normalizer' ]
autowire: true

PhpList\RestBundle\Subscription\Serializer\SubscriberListNormalizer:
tags: [ 'serializer.normalizer' ]
autowire: true

PhpList\RestBundle\Subscription\Serializer\SubscriberHistoryNormalizer:
tags: [ 'serializer.normalizer' ]
autowire: true

PhpList\RestBundle\Subscription\Serializer\SubscriptionNormalizer:
tags: [ 'serializer.normalizer' ]
autowire: true

PhpList\RestBundle\Messaging\Serializer\MessageNormalizer:
tags: [ 'serializer.normalizer' ]
autowire: true

PhpList\RestBundle\Messaging\Serializer\TemplateImageNormalizer:
tags: [ 'serializer.normalizer' ]
autowire: true

PhpList\RestBundle\Messaging\Serializer\TemplateNormalizer:
tags: [ 'serializer.normalizer' ]
autowire: true

PhpList\RestBundle\Messaging\Serializer\ListMessageNormalizer:
tags: [ 'serializer.normalizer' ]
autowire: true

PhpList\RestBundle\Identity\Serializer\AdministratorNormalizer:
tags: [ 'serializer.normalizer' ]
autowire: true

PhpList\RestBundle\Identity\Serializer\AdminAttributeDefinitionNormalizer:
tags: [ 'serializer.normalizer' ]
autowire: true

PhpList\RestBundle\Identity\Serializer\AdminAttributeValueNormalizer:
tags: [ 'serializer.normalizer' ]
autowire: true

PhpList\RestBundle\Subscription\Serializer\AttributeDefinitionNormalizer:
tags: [ 'serializer.normalizer' ]
autowire: true

PhpList\RestBundle\Subscription\Serializer\SubscriberAttributeValueNormalizer:
tags: [ 'serializer.normalizer' ]
autowire: true

PhpList\RestBundle\Common\Serializer\CursorPaginationNormalizer:
autowire: true

PhpList\RestBundle\Subscription\Serializer\SubscribersExportRequestNormalizer:
tags: [ 'serializer.normalizer' ]
autowire: true

PhpList\RestBundle\Statistics\Serializer\CampaignStatisticsNormalizer:
tags: [ 'serializer.normalizer' ]
autowire: true

PhpList\RestBundle\Statistics\Serializer\ViewOpensStatisticsNormalizer:
tags: [ 'serializer.normalizer' ]
autowire: true

PhpList\RestBundle\Statistics\Serializer\TopDomainsNormalizer:
tags: [ 'serializer.normalizer' ]
autowire: true

PhpList\RestBundle\Statistics\Serializer\TopLocalPartsNormalizer:
tags: [ 'serializer.normalizer' ]
autowire: true

PhpList\RestBundle\Subscription\Serializer\UserBlacklistNormalizer:
tags: [ 'serializer.normalizer' ]
autowire: true

PhpList\RestBundle\Subscription\Serializer\SubscribePageNormalizer:
tags: [ 'serializer.normalizer' ]
autowire: true

PhpList\RestBundle\Messaging\Serializer\BounceRegexNormalizer:
tags: [ 'serializer.normalizer' ]
autowire: true
PhpList\RestBundle\:
resource: '../../src/*/Serializer/*'
15 changes: 13 additions & 2 deletions config/services/services.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
services:
PhpList\RestBundle\Subscription\Service\SubscriberService:
PhpList\RestBundle\Subscription\Service\SubscriberHistoryService:
autowire: true
autoconfigure: true

PhpList\RestBundle\Subscription\Service\SubscriberHistoryService:
PhpList\Core\Domain\Messaging\Service\ForwardingGuard:
autowire: true
autoconfigure: true
public: false

PhpList\Core\Domain\Messaging\Service\ForwardDeliveryService:
autowire: true
autoconfigure: true
public: false

PhpList\Core\Domain\Messaging\Service\ForwardContentService:
autowire: true
autoconfigure: true
public: false
10 changes: 10 additions & 0 deletions config/services/validators.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,13 @@ services:
autowire: true
autoconfigure: true

PhpList\RestBundle\Messaging\Validator\Constraint\MaxForwardCountValidator:
autowire: true
autoconfigure: true
tags: [ 'validator.constraint_validator' ]

PhpList\RestBundle\Messaging\Validator\Constraint\MaxPersonalNoteSizeValidator:
autowire: true
autoconfigure: true
tags: [ 'validator.constraint_validator' ]

21 changes: 18 additions & 3 deletions src/Common/Dto/CursorPaginationResult.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,24 @@
class CursorPaginationResult
{
public function __construct(
public readonly array $items,
public readonly int $limit,
public readonly int $total,
private readonly array $items,
private readonly int $limit,
private readonly int $total,
) {
}

public function getItems(): array
{
return $this->items;
}

public function getLimit(): int
{
return $this->limit;
}

public function getTotal(): int
{
return $this->total;
}
}
81 changes: 40 additions & 41 deletions src/Common/EventListener/ExceptionListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@

use Exception;
use PhpList\Core\Domain\Identity\Exception\AdminAttributeCreationException;
use PhpList\Core\Domain\Messaging\Exception\AttachmentFileNotFoundException;
use PhpList\Core\Domain\Messaging\Exception\MessageNotReceivedException;
use PhpList\Core\Domain\Messaging\Exception\SubscriberNotFoundException;
use PhpList\Core\Domain\Subscription\Exception\AttributeDefinitionCreationException;
use PhpList\Core\Domain\Subscription\Exception\SubscriptionCreationException;
use Symfony\Component\HttpFoundation\JsonResponse;
Expand All @@ -17,53 +20,49 @@

class ExceptionListener
{
private const EXCEPTION_STATUS_MAP = [
SubscriptionCreationException::class => null,
AttributeDefinitionCreationException::class => null,
AdminAttributeCreationException::class => null,
ValidatorException::class => 400,
AccessDeniedException::class => 403,
AccessDeniedHttpException::class => 403,
AttachmentFileNotFoundException::class => 404,
SubscriberNotFoundException::class => 404,
MessageNotReceivedException::class => 422,
];

public function onKernelException(ExceptionEvent $event): void
{
$exception = $event->getThrowable();

if ($exception instanceof AccessDeniedHttpException) {
$response = new JsonResponse([
'message' => $exception->getMessage(),
], 403);

$event->setResponse($response);
} elseif ($exception instanceof HttpExceptionInterface) {
$response = new JsonResponse([
'message' => $exception->getMessage(),
], $exception->getStatusCode());
foreach (self::EXCEPTION_STATUS_MAP as $class => $statusCode) {
if ($exception instanceof $class) {
$status = $statusCode ?? $exception->getStatusCode();
$event->setResponse(
new JsonResponse([
'message' => $exception->getMessage()
], $status)
);
return;
}
}

$event->setResponse($response);
} elseif ($exception instanceof SubscriptionCreationException) {
$response = new JsonResponse([
'message' => $exception->getMessage(),
], $exception->getStatusCode());
$event->setResponse($response);
} elseif ($exception instanceof AdminAttributeCreationException) {
$response = new JsonResponse([
'message' => $exception->getMessage(),
], $exception->getStatusCode());
$event->setResponse($response);
} elseif ($exception instanceof AttributeDefinitionCreationException) {
$response = new JsonResponse([
'message' => $exception->getMessage(),
], $exception->getStatusCode());
$event->setResponse($response);
} elseif ($exception instanceof ValidatorException) {
$response = new JsonResponse([
'message' => $exception->getMessage(),
], 400);
$event->setResponse($response);
} elseif ($exception instanceof AccessDeniedException) {
$response = new JsonResponse([
'message' => $exception->getMessage(),
], 403);
$event->setResponse($response);
} elseif ($exception instanceof Exception) {
$response = new JsonResponse([
'message' => $exception->getMessage(),
], 500);
if ($exception instanceof HttpExceptionInterface) {
$event->setResponse(
new JsonResponse([
'message' => $exception->getMessage()
], $exception->getStatusCode())
);
return;
}

$event->setResponse($response);
if ($exception instanceof Exception) {
$event->setResponse(
new JsonResponse([
'message' => $exception->getMessage()
], 500)
);
}
}
}
6 changes: 3 additions & 3 deletions src/Common/Serializer/CursorPaginationNormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ class CursorPaginationNormalizer implements NormalizerInterface
*/
public function normalize($object, string $format = null, array $context = []): array
{
$items = $object->items;
$limit = $object->limit;
$total = $object->total;
$items = $object->getItems();
$limit = $object->getLimit();
$total = $object->getTotal();
$hasNext = !empty($items) && isset($items[array_key_last($items)]['id']);

return [
Expand Down
20 changes: 11 additions & 9 deletions src/Common/Service/Provider/PaginatedDataProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public function getPaginatedList(
Request $request,
NormalizerInterface $normalizer,
string $className,
FilterRequestInterface $filter = null
FilterRequestInterface $filter
): array {
$pagination = $this->paginationFactory->fromRequest($request);

Expand All @@ -37,20 +37,22 @@ public function getPaginatedList(
throw new RuntimeException('Repository not found');
}

$items = $repository->getFilteredAfterId(
lastId: $pagination->afterId,
limit: $pagination->limit,
filter: $filter,
);
$total = $repository->count();
$filter->setLimit($pagination->limit);
$filter->setLastId($pagination->afterId);

$result = $repository->getFilteredAfterId(filter: $filter);

$normalizedItems = array_map(
fn($item) => $normalizer->normalize($item, 'json'),
$items
$result->getItems()
);

return $this->paginationNormalizer->normalize(
new CursorPaginationResult($normalizedItems, $pagination->limit, $total)
new CursorPaginationResult(
items: $normalizedItems,
limit: $result->getLimit(),
total: $result->getTotal(),
)
);
}
}
Loading
Loading