diff --git a/.coderabbit.yaml b/.coderabbit.yaml index b354963b..edaddc74 100644 --- a/.coderabbit.yaml +++ b/.coderabbit.yaml @@ -14,3 +14,7 @@ reviews: base_branches: - ".*" drafts: false + +checks: + docstring_coverage: + enabled: false diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index aad3619f..0c6c6983 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,3 +1,3 @@ -"@coderabbitai summary" +@coderabbitai summary Thanks for contributing to phpList! diff --git a/src/Identity/OpenApi/SwaggerSchemasRequest.php b/src/Identity/OpenApi/SwaggerSchemasRequest.php deleted file mode 100644 index 3b32ded2..00000000 --- a/src/Identity/OpenApi/SwaggerSchemasRequest.php +++ /dev/null @@ -1,122 +0,0 @@ - true, 'campaigns' => false, 'statistics' => true, 'settings' => false] - ), - ], - type: 'object' -)] -#[OA\Schema( - schema: 'UpdateAdministratorRequest', - properties: [ - new OA\Property( - property: 'login_name', - type: 'string', - maxLength: 255, - minLength: 3, - example: 'admin' - ), - new OA\Property( - property: 'password', - type: 'string', - format: 'password', - maxLength: 255, - minLength: 6, - example: 'StrongP@ssw0rd' - ), - new OA\Property( - property: 'email', - type: 'string', - format: 'email', - example: 'admin@example.com' - ), - new OA\Property( - property: 'super_user', - type: 'boolean', - example: false - ), - new OA\Property( - property: 'privileges', - description: 'Array of privileges where keys are privilege names and values are booleans', - properties: [ - new OA\Property(property: 'subscribers', type: 'boolean', example: true), - new OA\Property(property: 'campaigns', type: 'boolean', example: false), - new OA\Property(property: 'statistics', type: 'boolean', example: true), - new OA\Property(property: 'settings', type: 'boolean', example: false), - ], - type: 'object', - example: ['subscribers' => true, 'campaigns' => false, 'statistics' => true, 'settings' => false] - ), - ], - type: 'object' -)] -#[OA\Schema( - schema: 'AdminAttributeDefinitionRequest', - required: ['name'], - properties: [ - new OA\Property(property: 'name', type: 'string', format: 'string', example: 'Country'), - new OA\Property( - property: 'type', - type: 'string', - enum: [ - AttributeTypeEnum::TextLine, - AttributeTypeEnum::Hidden, - ], - example: 'hidden', - nullable: true - ), - new OA\Property(property: 'order', type: 'number', example: 12), - new OA\Property(property: 'default_value', type: 'string', example: 'United States'), - new OA\Property(property: 'required', type: 'boolean', example: true), - ], - type: 'object' -)] -class SwaggerSchemasRequest -{ -} diff --git a/src/Identity/OpenApi/SwaggerSchemasResponse.php b/src/Identity/OpenApi/SwaggerSchemasResponse.php deleted file mode 100644 index 2d83cff0..00000000 --- a/src/Identity/OpenApi/SwaggerSchemasResponse.php +++ /dev/null @@ -1,48 +0,0 @@ - true, 'campaigns' => false, 'statistics' => true, 'settings' => false] + ), + ], + type: 'object' +)] class CreateAdministratorRequest implements RequestInterface { #[Assert\NotBlank] diff --git a/src/Identity/Request/UpdateAdministratorRequest.php b/src/Identity/Request/UpdateAdministratorRequest.php index de9d7258..f1432d49 100644 --- a/src/Identity/Request/UpdateAdministratorRequest.php +++ b/src/Identity/Request/UpdateAdministratorRequest.php @@ -4,14 +4,58 @@ namespace PhpList\RestBundle\Identity\Request; +use OpenApi\Attributes as OA; use PhpList\Core\Domain\Identity\Model\Administrator; use PhpList\Core\Domain\Identity\Model\Dto\UpdateAdministratorDto; -use PhpList\Core\Domain\Identity\Model\PrivilegeFlag; use PhpList\RestBundle\Common\Request\RequestInterface; use PhpList\RestBundle\Identity\Validator\Constraint\UniqueEmail; use PhpList\RestBundle\Identity\Validator\Constraint\UniqueLoginName; use Symfony\Component\Validator\Constraints as Assert; +#[OA\Schema( + schema: 'UpdateAdministratorRequest', + properties: [ + new OA\Property( + property: 'login_name', + type: 'string', + maxLength: 255, + minLength: 3, + example: 'admin' + ), + new OA\Property( + property: 'password', + type: 'string', + format: 'password', + maxLength: 255, + minLength: 6, + example: 'StrongP@ssw0rd' + ), + new OA\Property( + property: 'email', + type: 'string', + format: 'email', + example: 'admin@example.com' + ), + new OA\Property( + property: 'super_user', + type: 'boolean', + example: false + ), + new OA\Property( + property: 'privileges', + description: 'Array of privileges where keys are privilege names and values are booleans', + properties: [ + new OA\Property(property: 'subscribers', type: 'boolean', example: true), + new OA\Property(property: 'campaigns', type: 'boolean', example: false), + new OA\Property(property: 'statistics', type: 'boolean', example: true), + new OA\Property(property: 'settings', type: 'boolean', example: false), + ], + type: 'object', + example: ['subscribers' => true, 'campaigns' => false, 'statistics' => true, 'settings' => false] + ), + ], + type: 'object' +)] class UpdateAdministratorRequest implements RequestInterface { public int $administratorId; @@ -28,7 +72,7 @@ class UpdateAdministratorRequest implements RequestInterface public ?string $email = null; #[Assert\Type('bool')] - public ?bool $superAdmin = null; + public ?bool $superUser = null; /** * Array of privileges where keys are privilege names (from PrivilegeFlag enum) and values are booleans. @@ -49,7 +93,7 @@ public function getDto(): UpdateAdministratorDto loginName: $this->loginName, password: $this->password, email: $this->email, - superAdmin: $this->superAdmin, + superAdmin: $this->superUser, privileges: $this->privileges ); } diff --git a/src/Identity/Serializer/AdminAttributeDefinitionNormalizer.php b/src/Identity/Serializer/AdminAttributeDefinitionNormalizer.php index 2c13171c..68be95a4 100644 --- a/src/Identity/Serializer/AdminAttributeDefinitionNormalizer.php +++ b/src/Identity/Serializer/AdminAttributeDefinitionNormalizer.php @@ -4,9 +4,22 @@ namespace PhpList\RestBundle\Identity\Serializer; +use OpenApi\Attributes as OA; use PhpList\Core\Domain\Identity\Model\AdminAttributeDefinition; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; +#[OA\Schema( + schema: 'AdminAttributeDefinition', + properties: [ + new OA\Property(property: 'id', type: 'integer', example: 1), + new OA\Property(property: 'name', type: 'string', example: 'Country'), + new OA\Property(property: 'type', type: 'string', example: 'hidden'), + new OA\Property(property: 'list_order', type: 'integer', example: 12), + new OA\Property(property: 'default_value', type: 'string', example: 'United States'), + new OA\Property(property: 'required', type: 'boolean', example: true), + ], + type: 'object' +)] class AdminAttributeDefinitionNormalizer implements NormalizerInterface { /** @@ -25,7 +38,6 @@ public function normalize($object, string $format = null, array $context = []): 'list_order' => $object->getListOrder(), 'default_value' => $object->getDefaultValue(), 'required' => $object->isRequired(), - 'table_name' => $object->getTableName(), ]; } diff --git a/src/Identity/Serializer/AdminAttributeValueNormalizer.php b/src/Identity/Serializer/AdminAttributeValueNormalizer.php index abdc4ebf..d6a0fd72 100644 --- a/src/Identity/Serializer/AdminAttributeValueNormalizer.php +++ b/src/Identity/Serializer/AdminAttributeValueNormalizer.php @@ -4,9 +4,19 @@ namespace PhpList\RestBundle\Identity\Serializer; +use OpenApi\Attributes as OA; use PhpList\Core\Domain\Identity\Model\AdminAttributeValue; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; +#[OA\Schema( + schema: 'AdminAttributeValue', + properties: [ + new OA\Property(property: 'administrator', ref: '#/components/schemas/Administrator'), + new OA\Property(property: 'definition', ref: '#/components/schemas/AdminAttributeDefinition'), + new OA\Property(property: 'value', type: 'string', example: 'United States'), + ], + type: 'object' +)] class AdminAttributeValueNormalizer implements NormalizerInterface { public function __construct( diff --git a/src/Identity/Serializer/AdministratorNormalizer.php b/src/Identity/Serializer/AdministratorNormalizer.php index 5382bf1d..751bfe20 100644 --- a/src/Identity/Serializer/AdministratorNormalizer.php +++ b/src/Identity/Serializer/AdministratorNormalizer.php @@ -4,11 +4,29 @@ namespace PhpList\RestBundle\Identity\Serializer; +use OpenApi\Attributes as OA; use DateTimeInterface; use InvalidArgumentException; use PhpList\Core\Domain\Identity\Model\Administrator; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; +#[OA\Schema( + schema: 'Administrator', + properties: [ + new OA\Property(property: 'id', type: 'integer', example: 1), + new OA\Property(property: 'login_name', type: 'string', example: 'admin'), + new OA\Property(property: 'email', type: 'string', format: 'email', example: 'admin@example.com'), + new OA\Property(property: 'super_user', type: 'boolean', example: true), + new OA\Property(property: 'privileges', type: 'array', items: new OA\Items(type: 'string')), + new OA\Property( + property: 'created_at', + type: 'string', + format: 'date-time', + example: '2025-04-29T12:34:56+00:00' + ), + ], + type: 'object' +)] class AdministratorNormalizer implements NormalizerInterface { /** @@ -25,7 +43,7 @@ public function normalize($object, string $format = null, array $context = []): 'id' => $object->getId(), 'login_name' => $object->getLoginName(), 'email' => $object->getEmail(), - 'super_admin' => $object->isSuperUser(), + 'super_user' => $object->isSuperUser(), 'privileges' => $object->getPrivileges()->all(), 'created_at' => $object->getCreatedAt()?->format(DateTimeInterface::ATOM), ]; diff --git a/src/Messaging/OpenApi/SwaggerSchemasRequest.php b/src/Messaging/OpenApi/SwaggerSchemasRequest.php deleted file mode 100644 index 8aef4021..00000000 --- a/src/Messaging/OpenApi/SwaggerSchemasRequest.php +++ /dev/null @@ -1,82 +0,0 @@ -', - nullable: true - ), - new OA\Property(property: 'to_field', type: 'string', example: '', nullable: true), - new OA\Property(property: 'reply_to', type: 'string', nullable: true), - new OA\Property(property: 'user_selection', type: 'string', nullable: true), - ], - type: 'object' - ), - ], - type: 'object' -)] -#[OA\Schema( - schema: 'BounceRegex', - properties: [ - new OA\Property(property: 'id', type: 'integer', example: 10), - new OA\Property(property: 'regex', type: 'string', example: '/mailbox is full/i'), - new OA\Property(property: 'regex_hash', type: 'string', example: 'd41d8cd98f00b204e9800998ecf8427e'), - new OA\Property(property: 'action', type: 'string', example: 'delete', nullable: true), - new OA\Property(property: 'list_order', type: 'integer', example: 0, nullable: true), - new OA\Property(property: 'admin_id', type: 'integer', example: 1, nullable: true), - new OA\Property(property: 'comment', type: 'string', example: 'Auto-generated rule', nullable: true), - new OA\Property(property: 'status', type: 'string', example: 'active', nullable: true), - new OA\Property(property: 'count', type: 'integer', example: 5, nullable: true), - ], - type: 'object' -)] -class SwaggerSchemasResponse -{ -} diff --git a/src/Messaging/Request/Message/MessageContentRequest.php b/src/Messaging/Request/Message/MessageContentRequest.php index 93630584..a8d759ca 100644 --- a/src/Messaging/Request/Message/MessageContentRequest.php +++ b/src/Messaging/Request/Message/MessageContentRequest.php @@ -4,9 +4,21 @@ namespace PhpList\RestBundle\Messaging\Request\Message; +use OpenApi\Attributes as OA; use PhpList\Core\Domain\Messaging\Model\Dto\Message\MessageContentDto; use Symfony\Component\Validator\Constraints as Assert; +#[OA\Schema( + schema: 'MessageContentRequest', + required: ['subject', 'text', 'text_message', 'footer'], + properties: [ + new OA\Property(property: 'subject', type: 'string', example: 'Campaign Subject'), + new OA\Property(property: 'text', type: 'string', example: 'Full text content'), + new OA\Property(property: 'text_message', type: 'string', example: 'Short text message'), + new OA\Property(property: 'footer', type: 'string', example: 'Unsubscribe link here'), + ], + type: 'object' +)] class MessageContentRequest implements RequestDtoInterface { #[Assert\NotBlank] diff --git a/src/Messaging/Request/Message/MessageFormatRequest.php b/src/Messaging/Request/Message/MessageFormatRequest.php index 3dd20d87..4876706c 100644 --- a/src/Messaging/Request/Message/MessageFormatRequest.php +++ b/src/Messaging/Request/Message/MessageFormatRequest.php @@ -4,9 +4,30 @@ namespace PhpList\RestBundle\Messaging\Request\Message; +use OpenApi\Attributes as OA; use PhpList\Core\Domain\Messaging\Model\Dto\Message\MessageFormatDto; use Symfony\Component\Validator\Constraints as Assert; +#[OA\Schema( + schema: 'MessageFormatRequest', + required: ['html_formated', 'send_format', 'format_options'], + properties: [ + new OA\Property(property: 'html_formated', type: 'boolean', example: true), + new OA\Property( + property: 'send_format', + type: 'string', + enum: ['html', 'text', 'invite'], + example: 'html' + ), + new OA\Property( + property: 'format_options', + type: 'array', + items: new OA\Items(type: 'string', enum: ['text', 'html', 'pdf']), + example: ['html'] + ), + ], + type: 'object' +)] class MessageFormatRequest implements RequestDtoInterface { #[Assert\Type('bool')] diff --git a/src/Messaging/Request/Message/MessageMetadataRequest.php b/src/Messaging/Request/Message/MessageMetadataRequest.php index 03fd3323..7679d841 100644 --- a/src/Messaging/Request/Message/MessageMetadataRequest.php +++ b/src/Messaging/Request/Message/MessageMetadataRequest.php @@ -4,10 +4,18 @@ namespace PhpList\RestBundle\Messaging\Request\Message; +use OpenApi\Attributes as OA; use PhpList\Core\Domain\Messaging\Model\Dto\Message\MessageMetadataDto; use PhpList\Core\Domain\Messaging\Model\Message\MessageStatus; use Symfony\Component\Validator\Constraints as Assert; +#[OA\Schema( + schema: 'MessageMetadataRequest', + properties: [ + new OA\Property(property: 'status', type: 'string', example: 'draft'), + ], + type: 'object' +)] class MessageMetadataRequest implements RequestDtoInterface { #[Assert\NotBlank] diff --git a/src/Messaging/Request/Message/MessageOptionsRequest.php b/src/Messaging/Request/Message/MessageOptionsRequest.php index f2f34850..f7820e77 100644 --- a/src/Messaging/Request/Message/MessageOptionsRequest.php +++ b/src/Messaging/Request/Message/MessageOptionsRequest.php @@ -4,9 +4,21 @@ namespace PhpList\RestBundle\Messaging\Request\Message; +use OpenApi\Attributes as OA; use PhpList\Core\Domain\Messaging\Model\Dto\Message\MessageOptionsDto; use Symfony\Component\Validator\Constraints as Assert; +#[OA\Schema( + schema: 'MessageOptionsRequest', + required: ['from_field'], + properties: [ + new OA\Property(property: 'from_field', type: 'string', example: 'info@example.com'), + new OA\Property(property: 'to_field', type: 'string', example: 'subscriber@example.com'), + new OA\Property(property: 'reply_to', type: 'string', example: 'reply@example.com'), + new OA\Property(property: 'user_selection', type: 'string', example: 'all-active-users'), + ], + type: 'object' +)] class MessageOptionsRequest implements RequestDtoInterface { #[Assert\NotBlank] diff --git a/src/Messaging/Request/Message/MessageScheduleRequest.php b/src/Messaging/Request/Message/MessageScheduleRequest.php index ed6aa8ef..11082269 100644 --- a/src/Messaging/Request/Message/MessageScheduleRequest.php +++ b/src/Messaging/Request/Message/MessageScheduleRequest.php @@ -4,9 +4,32 @@ namespace PhpList\RestBundle\Messaging\Request\Message; +use OpenApi\Attributes as OA; use PhpList\Core\Domain\Messaging\Model\Dto\Message\MessageScheduleDto; use Symfony\Component\Validator\Constraints as Assert; +#[OA\Schema( + schema: 'MessageScheduleRequest', + required: ['embargo'], + properties: [ + new OA\Property(property: 'embargo', type: 'string', format: 'date-time', example: '2025-04-17 09:00:00'), + new OA\Property(property: 'repeat_interval', type: 'integer', example: '24 hours'), + new OA\Property( + property: 'repeat_until', + type: 'string', + format: 'date-time', + example: '2025-04-30T00:00:00+04:00' + ), + new OA\Property(property: 'requeue_interval', type: 'integer', example: '12 hours'), + new OA\Property( + property: 'requeue_until', + type: 'string', + format: 'date-time', + example: '2025-04-20T00:00:00+04:00' + ), + ], + type: 'object' +)] class MessageScheduleRequest implements RequestDtoInterface { public ?int $repeatInterval = null; diff --git a/src/Messaging/Serializer/BounceRegexNormalizer.php b/src/Messaging/Serializer/BounceRegexNormalizer.php index 5771bd8b..47d285fa 100644 --- a/src/Messaging/Serializer/BounceRegexNormalizer.php +++ b/src/Messaging/Serializer/BounceRegexNormalizer.php @@ -4,9 +4,25 @@ namespace PhpList\RestBundle\Messaging\Serializer; +use OpenApi\Attributes as OA; use PhpList\Core\Domain\Messaging\Model\BounceRegex; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; +#[OA\Schema( + schema: 'BounceRegex', + properties: [ + new OA\Property(property: 'id', type: 'integer', example: 10), + new OA\Property(property: 'regex', type: 'string', example: '/mailbox is full/i'), + new OA\Property(property: 'regex_hash', type: 'string', example: 'd41d8cd98f00b204e9800998ecf8427e'), + new OA\Property(property: 'action', type: 'string', example: 'delete', nullable: true), + new OA\Property(property: 'list_order', type: 'integer', example: 0, nullable: true), + new OA\Property(property: 'admin_id', type: 'integer', example: 1, nullable: true), + new OA\Property(property: 'comment', type: 'string', example: 'Auto-generated rule', nullable: true), + new OA\Property(property: 'status', type: 'string', example: 'active', nullable: true), + new OA\Property(property: 'count', type: 'integer', example: 5, nullable: true), + ], + type: 'object' +)] class BounceRegexNormalizer implements NormalizerInterface { /** diff --git a/src/Messaging/Serializer/ListMessageNormalizer.php b/src/Messaging/Serializer/ListMessageNormalizer.php index 85348278..514ead23 100644 --- a/src/Messaging/Serializer/ListMessageNormalizer.php +++ b/src/Messaging/Serializer/ListMessageNormalizer.php @@ -4,10 +4,32 @@ namespace PhpList\RestBundle\Messaging\Serializer; +use OpenApi\Attributes as OA; use PhpList\Core\Domain\Messaging\Model\ListMessage; use PhpList\RestBundle\Subscription\Serializer\SubscriberListNormalizer; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; +#[OA\Schema( + schema: 'ListMessage', + properties: [ + new OA\Property(property: 'id', type: 'integer', example: 1), + new OA\Property(property: 'message', ref: '#/components/schemas/Message'), + new OA\Property(property: 'subscriber_list', ref: '#/components/schemas/SubscriberList'), + new OA\Property( + property: 'created_at', + type: 'string', + format: 'date-time', + example: '2022-12-01T10:00:00Z' + ), + new OA\Property( + property: 'updated_at', + type: 'string', + format: 'date-time', + example: '2022-12-01T10:00:00Z' + ), + ], + type: 'object' +)] class ListMessageNormalizer implements NormalizerInterface { public function __construct( diff --git a/src/Messaging/Serializer/MessageNormalizer.php b/src/Messaging/Serializer/MessageNormalizer.php index dcad6358..5c1f3e60 100644 --- a/src/Messaging/Serializer/MessageNormalizer.php +++ b/src/Messaging/Serializer/MessageNormalizer.php @@ -4,9 +4,85 @@ namespace PhpList\RestBundle\Messaging\Serializer; +use OpenApi\Attributes as OA; use PhpList\Core\Domain\Messaging\Model\Message; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; +#[OA\Schema( + schema: 'Message', + properties: [ + new OA\Property(property: 'id', type: 'integer'), + new OA\Property(property: 'unique_id', type: 'string', example: '2df6b147-8470-45ed-8e4e-86aa01af400d'), + new OA\Property( + property: 'template', + ref: '#/components/schemas/Template', + nullable: true + ), + new OA\Property( + property: 'message_content', + properties: [ + new OA\Property(property: 'subject', type: 'string', example: 'Newsletter'), + new OA\Property(property: 'text', type: 'string', example: 'Hello World!'), + new OA\Property(property: 'text_message', type: 'string'), + new OA\Property(property: 'footer', type: 'string', example: 'This is a footer'), + ], + type: 'object' + ), + new OA\Property( + property: 'message_format', + properties: [ + new OA\Property(property: 'html_formated', type: 'boolean'), + new OA\Property(property: 'send_format', type: 'string', example: 'text', nullable: true), + new OA\Property( + property: 'format_options', + type: 'array', + items: new OA\Items(type: 'string'), + example: ['as_html', 'as_text'], + ), + ], + type: 'object' + ), + new OA\Property( + property: 'message_metadata', + properties: [ + new OA\Property(property: 'status', type: 'string', example: 'sent'), + new OA\Property(property: 'processed', type: 'bool', example: true), + new OA\Property(property: 'views', type: 'integer', example: 12), + new OA\Property(property: 'bounce_count', type: 'integer'), + new OA\Property(property: 'entered', type: 'string', format: 'date-time', nullable: true), + new OA\Property(property: 'sent', type: 'string', format: 'date-time', nullable: true), + ], + type: 'object' + ), + new OA\Property( + property: 'message_schedule', + properties: [ + new OA\Property(property: 'repeat_interval', type: 'string', nullable: true), + new OA\Property(property: 'repeat_until', type: 'string', format: 'date-time', nullable: true), + new OA\Property(property: 'requeue_interval', type: 'string', nullable: true), + new OA\Property(property: 'requeue_until', type: 'string', format: 'date-time', nullable: true), + new OA\Property(property: 'embargo', type: 'string', example: '2023-01-01T12:00:00Z', nullable: true), + ], + type: 'object' + ), + new OA\Property( + property: 'message_options', + properties: [ + new OA\Property( + property: 'from_field', + type: 'string', + example: ' My Name ', + nullable: true + ), + new OA\Property(property: 'to_field', type: 'string', example: '', nullable: true), + new OA\Property(property: 'reply_to', type: 'string', nullable: true), + new OA\Property(property: 'user_selection', type: 'string', nullable: true), + ], + type: 'object' + ), + ], + type: 'object' +)] class MessageNormalizer implements NormalizerInterface { public function __construct(private readonly TemplateNormalizer $templateNormalizer) diff --git a/src/Messaging/Serializer/TemplateImageNormalizer.php b/src/Messaging/Serializer/TemplateImageNormalizer.php index 64ced9a0..599471f3 100644 --- a/src/Messaging/Serializer/TemplateImageNormalizer.php +++ b/src/Messaging/Serializer/TemplateImageNormalizer.php @@ -4,9 +4,31 @@ namespace PhpList\RestBundle\Messaging\Serializer; +use OpenApi\Attributes as OA; use PhpList\Core\Domain\Messaging\Model\TemplateImage; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; +#[OA\Schema( + schema: 'TemplateImage', + properties: [ + new OA\Property(property: 'id', type: 'integer', example: 12), + new OA\Property(property: 'template_id', type: 'integer', example: 1), + new OA\Property(property: 'mimetype', type: 'string', example: 'image/png', nullable: true), + new OA\Property(property: 'filename', type: 'string', example: 'header.png', nullable: true), + new OA\Property( + property: 'data', + description: 'Base64-encoded image data', + type: 'string', + format: 'byte', + example: 'iVBORw0KGgoAAAANSUhEUgAAA...', + nullable: true + ), + new OA\Property(property: 'width', type: 'integer', example: 600, nullable: true), + new OA\Property(property: 'height', type: 'integer', example: 200, nullable: true), + ], + type: 'object', + nullable: true +)] class TemplateImageNormalizer implements NormalizerInterface { /** diff --git a/src/Messaging/Serializer/TemplateNormalizer.php b/src/Messaging/Serializer/TemplateNormalizer.php index 669f7a40..ea047e13 100644 --- a/src/Messaging/Serializer/TemplateNormalizer.php +++ b/src/Messaging/Serializer/TemplateNormalizer.php @@ -4,10 +4,29 @@ namespace PhpList\RestBundle\Messaging\Serializer; +use OpenApi\Attributes as OA; use PhpList\Core\Domain\Messaging\Model\Template; use PhpList\Core\Domain\Messaging\Model\TemplateImage; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; +#[OA\Schema( + schema: 'Template', + properties: [ + new OA\Property(property: 'id', type: 'integer', example: 1), + new OA\Property(property: 'title', type: 'string', example: 'Newsletter'), + new OA\Property(property: 'content', type: 'string', example: 'Hello World!', nullable: true), + new OA\Property(property: 'text', type: 'string', nullable: true), + new OA\Property(property: 'order', type: 'integer', nullable: true), + new OA\Property( + property: 'images', + type: 'array', + items: new OA\Items(ref: '#/components/schemas/TemplateImage'), + nullable: true + ), + ], + type: 'object', + nullable: true +)] class TemplateNormalizer implements NormalizerInterface { public function __construct(private readonly TemplateImageNormalizer $templateImageNormalizer) diff --git a/src/PhpListRestBundle.php b/src/PhpListRestBundle.php index 2d27fae1..a856c869 100644 --- a/src/PhpListRestBundle.php +++ b/src/PhpListRestBundle.php @@ -11,6 +11,7 @@ * This bundle provides the REST API for phpList. * * @author Oliver Klee + * @author Tatevik Grigoryan */ #[OA\Info( version: '1.0.0', @@ -28,6 +29,56 @@ url: 'https://www.phplist.com/api/v2', description: 'Production server' )] +#[OA\Schema( + schema: 'DetailedDomainStats', + properties: [ + new OA\Property( + property: 'domains', + type: 'array', + items: new OA\Items( + properties: [ + new OA\Property(property: 'domain', type: 'string'), + new OA\Property( + property: 'confirmed', + properties: [ + new OA\Property(property: 'count', type: 'integer'), + new OA\Property(property: 'percentage', type: 'number', format: 'float'), + ], + type: 'object' + ), + new OA\Property( + property: 'unconfirmed', + properties: [ + new OA\Property(property: 'count', type: 'integer'), + new OA\Property(property: 'percentage', type: 'number', format: 'float'), + ], + type: 'object' + ), + new OA\Property( + property: 'blacklisted', + properties: [ + new OA\Property(property: 'count', type: 'integer'), + new OA\Property(property: 'percentage', type: 'number', format: 'float'), + ], + type: 'object' + ), + new OA\Property( + property: 'total', + properties: [ + new OA\Property(property: 'count', type: 'integer'), + new OA\Property(property: 'percentage', type: 'number', format: 'float'), + ], + type: 'object' + ), + ], + type: 'object' + ) + ), + new OA\Property(property: 'total', type: 'integer'), + ], + type: 'object', + nullable: true +)] class PhpListRestBundle extends Bundle { } diff --git a/src/Statistics/OpenApi/SwaggerSchemasRequest.php b/src/Statistics/OpenApi/SwaggerSchemasRequest.php deleted file mode 100644 index 1dcb53ab..00000000 --- a/src/Statistics/OpenApi/SwaggerSchemasRequest.php +++ /dev/null @@ -1,9 +0,0 @@ - '\d+', 'definitionId' => '\d+'], methods: ['POST', 'PUT'] )] #[OA\Post( - path: '/api/v2/subscribers/attribute-values/{subscriberId}/{definitionId}', + path: '/api/v2/subscribers/{subscriberId}/attributes/{definitionId}', description: '🚧 **Status: Beta** – This method is under development. Avoid using in production. ' . 'Returns created/updated subscriber attribute.', - summary: 'Create/update a subscriber attribute.', + summary: 'Create/update a subscriber attribute value.', requestBody: new OA\RequestBody( description: 'Pass parameters to create subscriber attribute.', required: true, @@ -130,13 +130,13 @@ public function createOrUpdate( } #[Route( - path: '/{subscriberId}/{definitionId}', + path: '/{subscriberId}/attributes/{definitionId}', name: 'delete', requirements: ['subscriberId' => '\d+', 'definitionId' => '\d+'], methods: ['DELETE'] )] #[OA\Delete( - path: '/api/v2/subscribers/attribute-values/{subscriberId}/{definitionId}', + path: '/api/v2/subscribers/{subscriberId}/attributes/{definitionId}', description: '🚧 **Status: Beta** – This method is under development. Avoid using in production. ' . 'Deletes a single subscriber attribute.', summary: 'Deletes an attribute.', @@ -200,9 +200,9 @@ public function delete( return $this->json(null, Response::HTTP_NO_CONTENT); } - #[Route('/{subscriberId}', name: 'get_list', requirements: ['subscriberId' => '\d+'], methods: ['GET'])] + #[Route('/{subscriberId}/attributes', name: 'get_list', requirements: ['subscriberId' => '\d+'], methods: ['GET'])] #[OA\Get( - path: '/api/v2/subscribers/attribute-values/{subscriberId}', + path: '/api/v2/subscribers/{subscriberId}/attributes', description: '🚧 **Status: Beta** – This method is under development. Avoid using in production. ' . 'Returns a JSON list of all subscriber attributes.', summary: 'Gets a list of all subscriber attributes.', @@ -270,23 +270,23 @@ public function getPaginated( return $this->json( $this->paginatedDataProvider->getPaginatedList( - $request, - $this->normalizer, - SubscriberAttributeValue::class, - $filter + request: $request, + normalizer: $this->normalizer, + className: SubscriberAttributeValue::class, + filter: $filter ), Response::HTTP_OK ); } #[Route( - path: '/{subscriberId}/{definitionId}', + path: '/{subscriberId}/attributes/{definitionId}', name: 'get_one', requirements: ['subscriberId' => '\d+', 'definitionId' => '\d+'], methods: ['GET'] )] #[OA\Get( - path: '/api/v2/subscribers/attribute-values/{subscriberId}/{definitionId}', + path: '/api/v2/subscribers/{subscriberId}/attributes/{definitionId}', description: '🚧 **Status: Beta** – This method is under development. Avoid using in production. ' . 'Returns a single attribute.', summary: 'Gets subscriber attribute.', diff --git a/src/Subscription/OpenApi/SwaggerSchemasResponse.php b/src/Subscription/OpenApi/SwaggerSchemasResponse.php deleted file mode 100644 index 29ddca75..00000000 --- a/src/Subscription/OpenApi/SwaggerSchemasResponse.php +++ /dev/null @@ -1,171 +0,0 @@ - $object->getId(), 'ip' => $object->getIp(), 'created_at' => $object->getCreatedAt()->format('Y-m-d\TH:i:sP'), - 'summery' => $object->getSummary(), + 'summary' => $object->getSummary(), 'detail' => $object->getDetail(), 'system_info' => $object->getSystemInfo(), ]; diff --git a/src/Subscription/Serializer/SubscriberListNormalizer.php b/src/Subscription/Serializer/SubscriberListNormalizer.php index 601f9dba..b10f2640 100644 --- a/src/Subscription/Serializer/SubscriberListNormalizer.php +++ b/src/Subscription/Serializer/SubscriberListNormalizer.php @@ -4,9 +4,29 @@ namespace PhpList\RestBundle\Subscription\Serializer; +use OpenApi\Attributes as OA; use PhpList\Core\Domain\Subscription\Model\SubscriberList; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; +#[OA\Schema( + schema: 'SubscriberList', + properties: [ + new OA\Property(property: 'id', type: 'integer', example: 2), + new OA\Property(property: 'name', type: 'string', example: 'Newsletter'), + new OA\Property(property: 'description', type: 'string', example: 'Monthly updates'), + new OA\Property( + property: 'created_at', + type: 'string', + format: 'date-time', + example: '2022-12-01T10:00:00Z' + ), + new OA\Property(property: 'list_position', type: 'integer', example: 1), + new OA\Property(property: 'subject_prefix', type: 'string', example: 'Newsletter: '), + new OA\Property(property: 'public', type: 'boolean', example: true), + new OA\Property(property: 'category', type: 'string', example: 'News'), + ], + type: 'object' +)] class SubscriberListNormalizer implements NormalizerInterface { /** diff --git a/src/Subscription/Serializer/SubscriberNormalizer.php b/src/Subscription/Serializer/SubscriberNormalizer.php index 84353ff7..d64d7750 100644 --- a/src/Subscription/Serializer/SubscriberNormalizer.php +++ b/src/Subscription/Serializer/SubscriberNormalizer.php @@ -4,10 +4,36 @@ namespace PhpList\RestBundle\Subscription\Serializer; +use OpenApi\Attributes as OA; use PhpList\Core\Domain\Subscription\Model\Subscriber; use PhpList\Core\Domain\Subscription\Model\Subscription; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; +#[OA\Schema( + schema: 'Subscriber', + properties: [ + new OA\Property(property: 'id', type: 'integer', example: 1), + new OA\Property(property: 'email', type: 'string', example: 'subscriber@example.com'), + new OA\Property( + property: 'created_at', + type: 'string', + format: 'date-time', + example: '2023-01-01T12:00:00Z', + ), + new OA\Property(property: 'confirmed', type: 'boolean', example: true), + new OA\Property(property: 'blacklisted', type: 'boolean', example: false), + new OA\Property(property: 'bounce_count', type: 'integer', example: 0), + new OA\Property(property: 'unique_id', type: 'string', example: '69f4e92cf50eafca9627f35704f030f4'), + new OA\Property(property: 'html_email', type: 'boolean', example: true), + new OA\Property(property: 'disabled', type: 'boolean', example: false), + new OA\Property( + property: 'subscribed_lists', + type: 'array', + items: new OA\Items(ref: '#/components/schemas/SubscriberList') + ), + ], + type: 'object' +)] class SubscriberNormalizer implements NormalizerInterface { public function __construct(private readonly SubscriberListNormalizer $subscriberListNormalizer) diff --git a/src/Subscription/Serializer/SubscriberOnlyNormalizer.php b/src/Subscription/Serializer/SubscriberOnlyNormalizer.php index e4cc95a6..2227f3ef 100644 --- a/src/Subscription/Serializer/SubscriberOnlyNormalizer.php +++ b/src/Subscription/Serializer/SubscriberOnlyNormalizer.php @@ -4,9 +4,30 @@ namespace PhpList\RestBundle\Subscription\Serializer; +use OpenApi\Attributes as OA; use PhpList\Core\Domain\Subscription\Model\Subscriber; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; +#[OA\Schema( + schema: 'SubscriberOnly', + properties: [ + new OA\Property(property: 'id', type: 'integer', example: 1), + new OA\Property(property: 'email', type: 'string', example: 'subscriber@example.com'), + new OA\Property( + property: 'created_at', + type: 'string', + format: 'date-time', + example: '2023-01-01T12:00:00Z', + ), + new OA\Property(property: 'confirmed', type: 'boolean', example: true), + new OA\Property(property: 'blacklisted', type: 'boolean', example: false), + new OA\Property(property: 'bounce_count', type: 'integer', example: 0), + new OA\Property(property: 'unique_id', type: 'string', example: '69f4e92cf50eafca9627f35704f030f4'), + new OA\Property(property: 'html_email', type: 'boolean', example: true), + new OA\Property(property: 'disabled', type: 'boolean', example: false), + ], + type: 'object' +)] class SubscriberOnlyNormalizer implements NormalizerInterface { /** diff --git a/src/Subscription/Serializer/SubscriptionNormalizer.php b/src/Subscription/Serializer/SubscriptionNormalizer.php index 7f68a7e8..d4037290 100644 --- a/src/Subscription/Serializer/SubscriptionNormalizer.php +++ b/src/Subscription/Serializer/SubscriptionNormalizer.php @@ -4,9 +4,24 @@ namespace PhpList\RestBundle\Subscription\Serializer; +use OpenApi\Attributes as OA; use PhpList\Core\Domain\Subscription\Model\Subscription; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; +#[OA\Schema( + schema: 'Subscription', + properties: [ + new OA\Property(property: 'subscriber', ref: '#/components/schemas/SubscriberOnly'), + new OA\Property(property: 'subscriber_list', ref: '#/components/schemas/SubscriberList'), + new OA\Property( + property: 'subscription_date', + type: 'string', + format: 'date-time', + example: '2023-01-01T12:00:00Z', + ), + ], + type: 'object' +)] class SubscriptionNormalizer implements NormalizerInterface { private SubscriberOnlyNormalizer $subscriberNormalizer; diff --git a/tests/Integration/Subscription/Controller/SubscriberAttributeValueControllerTest.php b/tests/Integration/Subscription/Controller/SubscriberAttributeValueControllerTest.php index 4b1a84c3..419ea922 100644 --- a/tests/Integration/Subscription/Controller/SubscriberAttributeValueControllerTest.php +++ b/tests/Integration/Subscription/Controller/SubscriberAttributeValueControllerTest.php @@ -12,7 +12,6 @@ class SubscriberAttributeValueControllerTest extends AbstractTestController { - public function testControllerIsAvailableViaContainer(): void { self::assertInstanceOf( @@ -34,7 +33,7 @@ public function testCreateOrUpdateAttributeValue(): void $this->authenticatedJsonRequest( 'post', - '/api/v2/subscribers/attribute-values/' . $subscriberId . '/' . $definitionId, + '/api/v2/subscribers/' . $subscriberId . '/attributes/' . $definitionId, [], [], [], @@ -55,7 +54,7 @@ public function testDeleteAttributeValue(): void $this->authenticatedJsonRequest( 'delete', - '/api/v2/subscribers/attribute-values/1/1' + '/api/v2/subscribers/1/attributes/1' ); $this->assertHttpNoContent(); @@ -70,7 +69,7 @@ public function testGetPaginatedAttributes(): void $this->authenticatedJsonRequest( 'get', - '/api/v2/subscribers/attribute-values/1' + '/api/v2/subscribers/1/attributes' ); $this->assertHttpOkay(); @@ -83,7 +82,7 @@ public function testAttributeValueNotFoundReturns404(): void { $this->authenticatedJsonRequest( 'get', - '/api/v2/subscribers/attribute-values/999/999' + '/api/v2/subscribers/999/attributes/999' ); $this->assertHttpNotFound(); diff --git a/tests/Unit/Identity/Request/UpdateAdministratorRequestTest.php b/tests/Unit/Identity/Request/UpdateAdministratorRequestTest.php index 3eb52282..c8b9c739 100644 --- a/tests/Unit/Identity/Request/UpdateAdministratorRequestTest.php +++ b/tests/Unit/Identity/Request/UpdateAdministratorRequestTest.php @@ -17,7 +17,7 @@ public function testGetDtoReturnsCorrectDto(): void $request->loginName = 'testuser'; $request->password = 'password123'; $request->email = 'test@example.com'; - $request->superAdmin = true; + $request->superUser = true; $request->privileges = [ 'subscribers' => true, 'campaigns' => false, diff --git a/tests/Unit/Identity/Serializer/AdminAttributeDefinitionNormalizerTest.php b/tests/Unit/Identity/Serializer/AdminAttributeDefinitionNormalizerTest.php index f7ad2953..8bc4396b 100644 --- a/tests/Unit/Identity/Serializer/AdminAttributeDefinitionNormalizerTest.php +++ b/tests/Unit/Identity/Serializer/AdminAttributeDefinitionNormalizerTest.php @@ -32,7 +32,6 @@ public function testNormalizeReturnsExpectedArray(): void 'list_order' => 5, 'default_value' => 'default', 'required' => true, - 'table_name' => 'test_table', ], $data); } diff --git a/tests/Unit/Identity/Serializer/AdministratorNormalizerTest.php b/tests/Unit/Identity/Serializer/AdministratorNormalizerTest.php index 512fa5c9..68ee51c8 100644 --- a/tests/Unit/Identity/Serializer/AdministratorNormalizerTest.php +++ b/tests/Unit/Identity/Serializer/AdministratorNormalizerTest.php @@ -36,7 +36,7 @@ public function testNormalizeValidAdministrator(): void 'id' => 123, 'login_name' => 'admin', 'email' => 'admin@example.com', - 'super_admin' => true, + 'super_user' => true, 'privileges' => [ 'subscribers' => true, 'campaigns' => false,