diff --git a/composer.json b/composer.json index ba5526cd..89dbf442 100644 --- a/composer.json +++ b/composer.json @@ -36,7 +36,7 @@ }, "require": { "php": "^8.1", - "phplist/core": "dev-dev", + "phplist/core": "dev-subscribepage", "friendsofsymfony/rest-bundle": "*", "symfony/test-pack": "^1.0", "symfony/process": "^6.4", diff --git a/config/services/normalizers.yml b/config/services/normalizers.yml index a270a3f2..66ee7def 100644 --- a/config/services/normalizers.yml +++ b/config/services/normalizers.yml @@ -97,3 +97,7 @@ services: PhpList\RestBundle\Subscription\Serializer\UserBlacklistNormalizer: tags: [ 'serializer.normalizer' ] autowire: true + + PhpList\RestBundle\Subscription\Serializer\SubscribePageNormalizer: + tags: [ 'serializer.normalizer' ] + autowire: true diff --git a/src/Subscription/Controller/SubscribePageController.php b/src/Subscription/Controller/SubscribePageController.php new file mode 100644 index 00000000..8f3878c4 --- /dev/null +++ b/src/Subscription/Controller/SubscribePageController.php @@ -0,0 +1,433 @@ + '\\d+'], methods: ['GET'])] + #[OA\Get( + path: '/api/v2/subscribe-pages/{id}', + description: '🚧 **Status: Beta** – This method is under development. Avoid using in production.', + summary: 'Get subscribe page', + tags: ['subscriptions'], + parameters: [ + new OA\Parameter( + name: 'php-auth-pw', + description: 'Session key obtained from login', + in: 'header', + required: true, + schema: new OA\Schema(type: 'string') + ), + new OA\Parameter( + name: 'id', + description: 'Subscribe page ID', + in: 'path', + required: true, + schema: new OA\Schema(type: 'integer') + ) + ], + responses: [ + new OA\Response( + response: 200, + description: 'Success', + content: new OA\JsonContent(ref: '#/components/schemas/SubscribePage'), + ), + new OA\Response( + response: 403, + description: 'Failure', + content: new OA\JsonContent(ref: '#/components/schemas/UnauthorizedResponse') + ), + new OA\Response( + response: 404, + description: 'Not Found', + content: new OA\JsonContent(ref: '#/components/schemas/NotFoundErrorResponse') + ), + ] + )] + public function getPage( + Request $request, + #[MapEntity(mapping: ['id' => 'id'])] ?SubscribePage $page = null + ): JsonResponse { + $admin = $this->requireAuthentication($request); + if (!$admin->getPrivileges()->has(PrivilegeFlag::Subscribers)) { + throw $this->createAccessDeniedException('You are not allowed to view subscribe pages.'); + } + + if (!$page) { + throw $this->createNotFoundException('Subscribe page not found'); + } + + return $this->json($this->normalizer->normalize($page), Response::HTTP_OK); + } + + #[Route('', name: 'create', methods: ['POST'])] + #[OA\Post( + path: '/api/v2/subscribe-pages', + description: '🚧 **Status: Beta** – This method is under development. Avoid using in production.', + summary: 'Create subscribe page', + requestBody: new OA\RequestBody( + required: true, + content: new OA\JsonContent( + properties: [ + new OA\Property(property: 'title', type: 'string'), + new OA\Property(property: 'active', type: 'boolean', nullable: true), + ] + ) + ), + tags: ['subscriptions'], + parameters: [ + new OA\Parameter( + name: 'php-auth-pw', + description: 'Session key obtained from login', + in: 'header', + required: true, + schema: new OA\Schema(type: 'string') + ) + ], + responses: [ + new OA\Response( + response: 201, + description: 'Created', + content: new OA\JsonContent(ref: '#/components/schemas/SubscribePage') + ), + new OA\Response( + response: 403, + description: 'Failure', + content: new OA\JsonContent(ref: '#/components/schemas/UnauthorizedResponse') + ), + new OA\Response( + response: 422, + description: 'Validation failed', + content: new OA\JsonContent(ref: '#/components/schemas/ValidationErrorResponse') + ) + ] + )] + public function createPage(Request $request): JsonResponse + { + $admin = $this->requireAuthentication($request); + if (!$admin->getPrivileges()->has(PrivilegeFlag::Subscribers)) { + throw $this->createAccessDeniedException('You are not allowed to create subscribe pages.'); + } + + /** @var SubscribePageRequest $createRequest */ + $createRequest = $this->validator->validate($request, SubscribePageRequest::class); + + $page = $this->subscribePageManager->createPage($createRequest->title, $createRequest->active, $admin); + + return $this->json($this->normalizer->normalize($page), Response::HTTP_CREATED); + } + + #[Route('/{id}', name: 'update', requirements: ['id' => '\\d+'], methods: ['PUT'])] + #[OA\Put( + path: '/api/v2/subscribe-pages/{id}', + description: '🚧 **Status: Beta** – This method is under development. Avoid using in production.', + summary: 'Update subscribe page', + requestBody: new OA\RequestBody( + required: true, + content: new OA\JsonContent( + properties: [ + new OA\Property(property: 'title', type: 'string', nullable: true), + new OA\Property(property: 'active', type: 'boolean', nullable: true), + ] + ) + ), + tags: ['subscriptions'], + parameters: [ + new OA\Parameter( + name: 'php-auth-pw', + description: 'Session key obtained from login', + in: 'header', + required: true, + schema: new OA\Schema(type: 'string') + ), + new OA\Parameter( + name: 'id', + description: 'Subscribe page ID', + in: 'path', + required: true, + schema: new OA\Schema(type: 'integer') + ) + ], + responses: [ + new OA\Response( + response: 200, + description: 'Success', + content: new OA\JsonContent(ref: '#/components/schemas/SubscribePage') + ), + new OA\Response( + response: 403, + description: 'Failure', + content: new OA\JsonContent(ref: '#/components/schemas/UnauthorizedResponse') + ), + new OA\Response( + response: 404, + description: 'Not Found', + content: new OA\JsonContent(ref: '#/components/schemas/NotFoundErrorResponse') + ), + ] + )] + public function updatePage( + Request $request, + #[MapEntity(mapping: ['id' => 'id'])] ?SubscribePage $page = null + ): JsonResponse { + $admin = $this->requireAuthentication($request); + if (!$admin->getPrivileges()->has(PrivilegeFlag::Subscribers)) { + throw $this->createAccessDeniedException('You are not allowed to update subscribe pages.'); + } + + if (!$page) { + throw $this->createNotFoundException('Subscribe page not found'); + } + + /** @var SubscribePageRequest $updateRequest */ + $updateRequest = $this->validator->validate($request, SubscribePageRequest::class); + + $updated = $this->subscribePageManager->updatePage( + page: $page, + title: $updateRequest->title, + active: $updateRequest->active, + owner: $admin, + ); + + return $this->json($this->normalizer->normalize($updated), Response::HTTP_OK); + } + + #[Route('/{id}', name: 'delete', requirements: ['id' => '\\d+'], methods: ['DELETE'])] + #[OA\Delete( + path: '/api/v2/subscribe-pages/{id}', + description: '🚧 **Status: Beta** – This method is under development. Avoid using in production.', + summary: 'Delete subscribe page', + tags: ['subscriptions'], + parameters: [ + new OA\Parameter( + name: 'php-auth-pw', + description: 'Session key obtained from login', + in: 'header', + required: true, + schema: new OA\Schema(type: 'string') + ), + new OA\Parameter( + name: 'id', + description: 'Subscribe page ID', + in: 'path', + required: true, + schema: new OA\Schema(type: 'integer') + ) + ], + responses: [ + new OA\Response(response: 204, description: 'No Content'), + new OA\Response( + response: 403, + description: 'Failure', + content: new OA\JsonContent(ref: '#/components/schemas/UnauthorizedResponse') + ), + new OA\Response( + response: 404, + description: 'Not Found', + content: new OA\JsonContent(ref: '#/components/schemas/NotFoundErrorResponse') + ) + ] + )] + public function deletePage( + Request $request, + #[MapEntity(mapping: ['id' => 'id'])] ?SubscribePage $page = null + ): JsonResponse { + $admin = $this->requireAuthentication($request); + if (!$admin->getPrivileges()->has(PrivilegeFlag::Subscribers)) { + throw $this->createAccessDeniedException('You are not allowed to delete subscribe pages.'); + } + + if ($page === null) { + throw $this->createNotFoundException('Subscribe page not found'); + } + + $this->subscribePageManager->deletePage($page); + + return $this->json(null, Response::HTTP_NO_CONTENT); + } + + #[Route('/{id}/data', name: 'get_data', requirements: ['id' => '\\d+'], methods: ['GET'])] + #[OA\Get( + path: '/api/v2/subscribe-pages/{id}/data', + description: '🚧 **Status: Beta** – This method is under development. Avoid using in production.', + summary: 'Get subscribe page data', + tags: ['subscriptions'], + parameters: [ + new OA\Parameter( + name: 'php-auth-pw', + description: 'Session key obtained from login', + in: 'header', + required: true, + schema: new OA\Schema(type: 'string') + ), + new OA\Parameter( + name: 'id', + description: 'Subscribe page ID', + in: 'path', + required: true, + schema: new OA\Schema(type: 'integer') + ) + ], + responses: [ + new OA\Response( + response: 200, + description: 'Success', + content: new OA\JsonContent( + type: 'array', + items: new OA\Items( + properties: [ + new OA\Property(property: 'id', type: 'integer'), + new OA\Property(property: 'name', type: 'string'), + new OA\Property(property: 'data', type: 'string', nullable: true), + ], + type: 'object' + ) + ) + ), + new OA\Response( + response: 403, + description: 'Failure', + content: new OA\JsonContent(ref: '#/components/schemas/UnauthorizedResponse') + ), + new OA\Response( + response: 404, + description: 'Not Found', + content: new OA\JsonContent(ref: '#/components/schemas/NotFoundErrorResponse') + ) + ] + )] + public function getPageData( + Request $request, + #[MapEntity(mapping: ['id' => 'id'])] ?SubscribePage $page = null + ): JsonResponse { + $admin = $this->requireAuthentication($request); + if (!$admin->getPrivileges()->has(PrivilegeFlag::Subscribers)) { + throw $this->createAccessDeniedException('You are not allowed to view subscribe page data.'); + } + + if (!$page) { + throw $this->createNotFoundException('Subscribe page not found'); + } + + $data = $this->subscribePageManager->getPageData($page); + + $json = array_map(static function ($item) { + return [ + 'id' => $item->getId(), + 'name' => $item->getName(), + 'data' => $item->getData(), + ]; + }, $data); + + return $this->json($json, Response::HTTP_OK); + } + + #[Route('/{id}/data', name: 'set_data', requirements: ['id' => '\\d+'], methods: ['PUT'])] + #[OA\Put( + path: '/api/v2/subscribe-pages/{id}/data', + description: '🚧 **Status: Beta** – This method is under development. Avoid using in production.', + summary: 'Set subscribe page data item', + requestBody: new OA\RequestBody( + required: true, + content: new OA\JsonContent( + properties: [ + new OA\Property(property: 'name', type: 'string'), + new OA\Property(property: 'value', type: 'string', nullable: true), + ] + ) + ), + tags: ['subscriptions'], + parameters: [ + new OA\Parameter( + name: 'php-auth-pw', + description: 'Session key obtained from login', + in: 'header', + required: true, + schema: new OA\Schema(type: 'string') + ), + new OA\Parameter( + name: 'id', + description: 'Subscribe page ID', + in: 'path', + required: true, + schema: new OA\Schema(type: 'integer') + ) + ], + responses: [ + new OA\Response( + response: 200, + description: 'Success', + content: new OA\JsonContent( + properties: [ + new OA\Property(property: 'id', type: 'integer'), + new OA\Property(property: 'name', type: 'string'), + new OA\Property(property: 'data', type: 'string', nullable: true), + ], + type: 'object' + ) + ), + new OA\Response( + response: 403, + description: 'Failure', + content: new OA\JsonContent(ref: '#/components/schemas/UnauthorizedResponse') + ), + new OA\Response( + response: 404, + description: 'Not Found', + content: new OA\JsonContent(ref: '#/components/schemas/NotFoundErrorResponse') + ) + ] + )] + public function setPageData( + Request $request, + #[MapEntity(mapping: ['id' => 'id'])] ?SubscribePage $page = null + ): JsonResponse { + $admin = $this->requireAuthentication($request); + if (!$admin->getPrivileges()->has(PrivilegeFlag::Subscribers)) { + throw $this->createAccessDeniedException('You are not allowed to update subscribe page data.'); + } + + if (!$page) { + throw $this->createNotFoundException('Subscribe page not found'); + } + + /** @var SubscribePageDataRequest $createRequest */ + $createRequest = $this->validator->validate($request, SubscribePageDataRequest::class); + + $item = $this->subscribePageManager->setPageData($page, $createRequest->name, $createRequest->value); + + return $this->json([ + 'id' => $item->getId(), + 'name' => $item->getName(), + 'data' => $item->getData(), + ], Response::HTTP_OK); + } +} diff --git a/src/Subscription/OpenApi/SwaggerSchemasResponse.php b/src/Subscription/OpenApi/SwaggerSchemasResponse.php index 83764956..ac7eedfb 100644 --- a/src/Subscription/OpenApi/SwaggerSchemasResponse.php +++ b/src/Subscription/OpenApi/SwaggerSchemasResponse.php @@ -142,6 +142,15 @@ ), ], )] +#[OA\Schema( + schema: 'SubscribePage', + properties: [ + new OA\Property(property: 'id', type: 'integer', example: 1), + new OA\Property(property: 'title', type: 'string', example: 'Subscribe to our newsletter'), + new OA\Property(property: 'active', type: 'boolean', example: true), + new OA\Property(property: 'owner', ref: '#/components/schemas/Administrator'), + ], +)] class SwaggerSchemasResponse { } diff --git a/src/Subscription/Request/SubscribePageDataRequest.php b/src/Subscription/Request/SubscribePageDataRequest.php new file mode 100644 index 00000000..9af2ec08 --- /dev/null +++ b/src/Subscription/Request/SubscribePageDataRequest.php @@ -0,0 +1,21 @@ + $object->getId(), + 'title' => $object->getTitle(), + 'active' => $object->isActive(), + 'owner' => $this->adminNormalizer->normalize($object->getOwner()), + ]; + } + + /** + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function supportsNormalization($data, string $format = null): bool + { + return $data instanceof SubscribePage; + } +} diff --git a/tests/Integration/Subscription/Controller/SubscribePageControllerTest.php b/tests/Integration/Subscription/Controller/SubscribePageControllerTest.php new file mode 100644 index 00000000..d9da7b15 --- /dev/null +++ b/tests/Integration/Subscription/Controller/SubscribePageControllerTest.php @@ -0,0 +1,291 @@ +get(SubscribePageController::class) + ); + } + + public function testGetSubscribePageWithoutSessionReturnsForbidden(): void + { + $this->loadFixtures([AdministratorFixture::class, SubscribePageFixture::class]); + + self::getClient()->request('GET', '/api/v2/subscribe-pages/1'); + $this->assertHttpForbidden(); + } + + public function testGetSubscribePageWithSessionReturnsPage(): void + { + $this->loadFixtures([ + AdministratorFixture::class, + AdministratorTokenFixture::class, + SubscribePageFixture::class, + ]); + + $this->authenticatedJsonRequest('GET', '/api/v2/subscribe-pages/1'); + + $this->assertHttpOkay(); + $data = $this->getDecodedJsonResponseContent(); + + self::assertSame(1, $data['id']); + self::assertSame('Welcome Page', $data['title']); + self::assertTrue($data['active']); + self::assertIsArray($data['owner']); + self::assertSame(1, $data['owner']['id']); + self::assertArrayHasKey('login_name', $data['owner']); + self::assertArrayHasKey('email', $data['owner']); + self::assertArrayHasKey('privileges', $data['owner']); + } + + public function testGetSubscribePageWithSessionNotFound(): void + { + $this->loadFixtures([ + AdministratorFixture::class, + AdministratorTokenFixture::class, + SubscribePageFixture::class, + ]); + + $this->authenticatedJsonRequest('GET', '/api/v2/subscribe-pages/9999'); + + $this->assertHttpNotFound(); + } + + public function testCreateSubscribePageWithoutSessionReturnsForbidden(): void + { + // no auth fixtures loaded here + $payload = json_encode([ + 'title' => 'new-page@example.org', + 'active' => true, + ], JSON_THROW_ON_ERROR); + + $this->jsonRequest('POST', '/api/v2/subscribe-pages', content: $payload); + + $this->assertHttpForbidden(); + } + + public function testCreateSubscribePageWithSessionCreatesPage(): void + { + $payload = json_encode([ + 'title' => 'new-page@example.org', + 'active' => true, + ], JSON_THROW_ON_ERROR); + + $this->authenticatedJsonRequest('POST', '/api/v2/subscribe-pages', content: $payload); + + $this->assertHttpCreated(); + $data = $this->getDecodedJsonResponseContent(); + + self::assertArrayHasKey('id', $data); + self::assertIsInt($data['id']); + self::assertGreaterThanOrEqual(1, $data['id']); + self::assertSame('new-page@example.org', $data['title']); + self::assertTrue($data['active']); + self::assertIsArray($data['owner']); + self::assertArrayHasKey('id', $data['owner']); + self::assertArrayHasKey('login_name', $data['owner']); + self::assertArrayHasKey('email', $data['owner']); + self::assertArrayHasKey('privileges', $data['owner']); + } + + public function testUpdateSubscribePageWithoutSessionReturnsForbidden(): void + { + $this->loadFixtures([AdministratorFixture::class, SubscribePageFixture::class]); + $payload = json_encode([ + 'title' => 'updated-page@example.org', + 'active' => false, + ], JSON_THROW_ON_ERROR); + + $this->jsonRequest('PUT', '/api/v2/subscribe-pages/1', content: $payload); + $this->assertHttpForbidden(); + } + + public function testUpdateSubscribePageWithSessionReturnsOk(): void + { + $this->loadFixtures([ + AdministratorFixture::class, + AdministratorTokenFixture::class, + SubscribePageFixture::class, + ]); + $payload = json_encode([ + 'title' => 'updated-page@example.org', + 'active' => false, + ], JSON_THROW_ON_ERROR); + + $this->authenticatedJsonRequest('PUT', '/api/v2/subscribe-pages/1', content: $payload); + + $this->assertHttpOkay(); + $data = $this->getDecodedJsonResponseContent(); + self::assertSame(1, $data['id']); + self::assertSame('updated-page@example.org', $data['title']); + self::assertFalse($data['active']); + self::assertIsArray($data['owner']); + } + + public function testUpdateSubscribePageWithSessionNotFound(): void + { + $this->loadFixtures([ + AdministratorFixture::class, + AdministratorTokenFixture::class, + SubscribePageFixture::class, + ]); + $payload = json_encode([ + 'title' => 'updated-page@example.org', + 'active' => false, + ], JSON_THROW_ON_ERROR); + + $this->authenticatedJsonRequest('PUT', '/api/v2/subscribe-pages/9999', content: $payload); + $this->assertHttpNotFound(); + } + + public function testDeleteSubscribePageWithoutSessionReturnsForbidden(): void + { + $this->loadFixtures([AdministratorFixture::class, SubscribePageFixture::class]); + $this->jsonRequest('DELETE', '/api/v2/subscribe-pages/1'); + $this->assertHttpForbidden(); + } + + public function testDeleteSubscribePageWithSessionReturnsNoContentAndRemovesResource(): void + { + $this->loadFixtures([ + AdministratorFixture::class, + AdministratorTokenFixture::class, + SubscribePageFixture::class, + ]); + + $this->authenticatedJsonRequest('DELETE', '/api/v2/subscribe-pages/1'); + $this->assertHttpNoContent(); + + $this->authenticatedJsonRequest('GET', '/api/v2/subscribe-pages/1'); + $this->assertHttpNotFound(); + } + + public function testDeleteSubscribePageWithSessionNotFound(): void + { + $this->loadFixtures([ + AdministratorFixture::class, + AdministratorTokenFixture::class, + SubscribePageFixture::class, + ]); + + $this->authenticatedJsonRequest('DELETE', '/api/v2/subscribe-pages/9999'); + $this->assertHttpNotFound(); + } + + public function testGetSubscribePageDataWithoutSessionReturnsForbidden(): void + { + $this->loadFixtures([AdministratorFixture::class, SubscribePageFixture::class]); + $this->jsonRequest('GET', '/api/v2/subscribe-pages/1/data'); + $this->assertHttpForbidden(); + } + + public function testGetSubscribePageDataWithSessionReturnsArray(): void + { + $this->loadFixtures([ + AdministratorFixture::class, + AdministratorTokenFixture::class, + SubscribePageFixture::class, + ]); + + $this->authenticatedJsonRequest('GET', '/api/v2/subscribe-pages/1/data'); + $this->assertHttpOkay(); + $data = $this->getDecodedJsonResponseContent(); + self::assertIsArray($data); + + if (!empty($data)) { + self::assertArrayHasKey('id', $data[0]); + self::assertArrayHasKey('name', $data[0]); + self::assertArrayHasKey('data', $data[0]); + } + } + + public function testGetSubscribePageDataWithSessionNotFound(): void + { + $this->loadFixtures([ + AdministratorFixture::class, + AdministratorTokenFixture::class, + SubscribePageFixture::class, + ]); + + $this->authenticatedJsonRequest('GET', '/api/v2/subscribe-pages/9999/data'); + $this->assertHttpNotFound(); + } + + public function testSetSubscribePageDataWithoutSessionReturnsForbidden(): void + { + $this->loadFixtures([AdministratorFixture::class, SubscribePageFixture::class]); + $payload = json_encode([ + 'name' => 'intro_text', + 'value' => 'Hello world', + ], JSON_THROW_ON_ERROR); + + $this->jsonRequest('PUT', '/api/v2/subscribe-pages/1/data', content: $payload); + $this->assertHttpForbidden(); + } + + public function testSetSubscribePageDataWithMissingNameReturnsUnprocessableEntity(): void + { + $this->loadFixtures([ + AdministratorFixture::class, + AdministratorTokenFixture::class, + SubscribePageFixture::class, + ]); + $payload = json_encode([ + 'value' => 'Hello world', + ], JSON_THROW_ON_ERROR); + + $this->authenticatedJsonRequest('PUT', '/api/v2/subscribe-pages/1/data', content: $payload); + $this->assertHttpUnprocessableEntity(); + } + + public function testSetSubscribePageDataWithSessionReturnsOk(): void + { + $this->loadFixtures([ + AdministratorFixture::class, + AdministratorTokenFixture::class, + SubscribePageFixture::class, + ]); + $payload = json_encode([ + 'name' => 'intro_text', + 'value' => 'Hello world', + ], JSON_THROW_ON_ERROR); + + $this->authenticatedJsonRequest('PUT', '/api/v2/subscribe-pages/1/data', content: $payload); + $this->assertHttpOkay(); + $data = $this->getDecodedJsonResponseContent(); + self::assertArrayHasKey('id', $data); + self::assertArrayHasKey('name', $data); + self::assertArrayHasKey('data', $data); + self::assertSame('intro_text', $data['name']); + self::assertSame('Hello world', $data['data']); + } + + public function testSetSubscribePageDataWithSessionNotFound(): void + { + $this->loadFixtures([ + AdministratorFixture::class, + AdministratorTokenFixture::class, + SubscribePageFixture::class, + ]); + $payload = json_encode([ + 'name' => 'intro_text', + 'value' => 'Hello world', + ], JSON_THROW_ON_ERROR); + + $this->authenticatedJsonRequest('PUT', '/api/v2/subscribe-pages/9999/data', content: $payload); + $this->assertHttpNotFound(); + } +} diff --git a/tests/Integration/Subscription/Fixtures/SubscribePage.csv b/tests/Integration/Subscription/Fixtures/SubscribePage.csv new file mode 100644 index 00000000..6279b9c4 --- /dev/null +++ b/tests/Integration/Subscription/Fixtures/SubscribePage.csv @@ -0,0 +1,3 @@ +id,title,active,owner +1,"Welcome Page",1,1 +2,"Inactive Page",0,1 diff --git a/tests/Integration/Subscription/Fixtures/SubscribePageFixture.php b/tests/Integration/Subscription/Fixtures/SubscribePageFixture.php new file mode 100644 index 00000000..a22b2465 --- /dev/null +++ b/tests/Integration/Subscription/Fixtures/SubscribePageFixture.php @@ -0,0 +1,62 @@ +getRepository(Administrator::class); + + do { + $data = fgetcsv($handle); + if ($data === false) { + break; + } + $row = array_combine($headers, $data); + + $owner = $adminRepository->find($row['owner']); + if ($owner === null) { + $owner = new Administrator(); + $this->setSubjectId($owner, (int)$row['owner']); + $owner->setSuperUser(true); + $owner->setDisabled(false); + $manager->persist($owner); + } + + $page = new SubscribePage(); + $this->setSubjectId($page, (int)$row['id']); + $page->setTitle($row['title']); + $page->setActive((bool)$row['active']); + $page->setOwner($owner); + + $manager->persist($page); + } while (true); + + fclose($handle); + } +} diff --git a/tests/Unit/Subscription/Serializer/SubscribePageNormalizerTest.php b/tests/Unit/Subscription/Serializer/SubscribePageNormalizerTest.php new file mode 100644 index 00000000..523e5904 --- /dev/null +++ b/tests/Unit/Subscription/Serializer/SubscribePageNormalizerTest.php @@ -0,0 +1,71 @@ +createMock(AdministratorNormalizer::class); + $normalizer = new SubscribePageNormalizer($adminNormalizer); + + $page = $this->createMock(SubscribePage::class); + + $this->assertTrue($normalizer->supportsNormalization($page)); + $this->assertFalse($normalizer->supportsNormalization(new stdClass())); + } + + public function testNormalizeReturnsExpectedArray(): void + { + $owner = $this->createMock(Administrator::class); + + $page = $this->createMock(SubscribePage::class); + $page->method('getId')->willReturn(42); + $page->method('getTitle')->willReturn('welcome@example.org'); + $page->method('isActive')->willReturn(true); + $page->method('getOwner')->willReturn($owner); + + $adminData = [ + 'id' => 7, + 'login_name' => 'admin', + 'email' => 'admin@example.org', + 'privileges' => [ + 'subscribers' => true, + 'campaigns' => false, + 'statistics' => true, + 'settings' => false, + ], + ]; + + $adminNormalizer = $this->createMock(AdministratorNormalizer::class); + $adminNormalizer->method('normalize')->with($owner)->willReturn($adminData); + + $normalizer = new SubscribePageNormalizer($adminNormalizer); + + $expected = [ + 'id' => 42, + 'title' => 'welcome@example.org', + 'active' => true, + 'owner' => $adminData, + ]; + + $this->assertSame($expected, $normalizer->normalize($page)); + } + + public function testNormalizeWithInvalidObjectReturnsEmptyArray(): void + { + $adminNormalizer = $this->createMock(AdministratorNormalizer::class); + $normalizer = new SubscribePageNormalizer($adminNormalizer); + + $this->assertSame([], $normalizer->normalize(new stdClass())); + } +}