Skip to content

Commit d7b9464

Browse files
committed
ISSUE-345: use post for export add tests
1 parent e032f5a commit d7b9464

File tree

6 files changed

+333
-46
lines changed

6 files changed

+333
-46
lines changed

src/Subscription/Controller/SubscriberExportController.php

Lines changed: 7 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,16 @@ public function __construct(
2828
$this->exportManager = $exportManager;
2929
}
3030

31-
#[Route('/export', name: 'csv', methods: ['GET'])]
32-
#[OA\Get(
31+
#[Route('/export', name: 'csv', methods: ['POST'])]
32+
#[OA\Post(
3333
path: '/subscribers/export',
3434
description: 'Export subscribers to CSV file.',
3535
summary: 'Export subscribers',
36+
requestBody: new OA\RequestBody(
37+
description: 'Filter parameters for subscribers to export. ',
38+
required: true,
39+
content: new OA\JsonContent(ref: '#/components/schemas/ExportSubscriberRequest')
40+
),
3641
tags: ['subscribers'],
3742
parameters: [
3843
new OA\Parameter(
@@ -42,48 +47,6 @@ public function __construct(
4247
required: true,
4348
schema: new OA\Schema(type: 'string')
4449
),
45-
new OA\Parameter(
46-
name: 'date_type',
47-
description: 'What date needs to be used for filtering (any, signup, changed, changelog, subscribed)',
48-
in: 'query',
49-
required: false,
50-
schema: new OA\Schema(
51-
type: 'string',
52-
default: 'any',
53-
enum: ['any', 'signup', 'changed', 'changelog', 'subscribed']
54-
)
55-
),
56-
new OA\Parameter(
57-
name: 'list_id',
58-
description: 'List ID from where to export',
59-
in: 'query',
60-
required: false,
61-
schema: new OA\Schema(type: 'integer')
62-
),
63-
new OA\Parameter(
64-
name: 'date_from',
65-
description: 'Start date for filtering (format: Y-m-d)',
66-
in: 'query',
67-
required: false,
68-
schema: new OA\Schema(type: 'string', format: 'date')
69-
),
70-
new OA\Parameter(
71-
name: 'date_to',
72-
description: 'End date for filtering (format: Y-m-d)',
73-
in: 'query',
74-
required: false,
75-
schema: new OA\Schema(type: 'string', format: 'date')
76-
),
77-
new OA\Parameter(
78-
name: 'columns',
79-
description: 'Columns to include in the export (comma-separated)',
80-
in: 'query',
81-
required: false,
82-
schema: new OA\Schema(
83-
type: 'string',
84-
default: 'id,email,confirmed,blacklisted,bounceCount,createdAt,updatedAt,uniqueId,htmlEmail,disabled,extraData'
85-
)
86-
)
8750
],
8851
responses: [
8952
new OA\Response(

src/Subscription/OpenApi/SwaggerSchemasRequest.php

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,55 @@
5353
],
5454
type: 'object'
5555
)]
56+
#[OA\Schema(
57+
schema: 'ExportSubscriberRequest',
58+
properties: [
59+
new OA\Property(
60+
property: 'date_type',
61+
description: 'What date needs to be used for filtering (any, signup, changed, changelog, subscribed)',
62+
default: 'any',
63+
enum: ['any', 'signup', 'changed', 'changelog', 'subscribed']
64+
),
65+
new OA\Property(
66+
property: 'list_id',
67+
description: 'List ID from where to export',
68+
type: 'integer'
69+
),
70+
new OA\Property(
71+
property: 'date_from',
72+
description: 'Start date for filtering (format: Y-m-d)',
73+
type: 'string',
74+
format: 'date'
75+
),
76+
new OA\Property(
77+
property: 'date_to',
78+
description: 'End date for filtering (format: Y-m-d)',
79+
type: 'string',
80+
format: 'date'
81+
),
82+
new OA\Property(
83+
property: 'columns',
84+
description: 'Columns to include in the export',
85+
type: 'array',
86+
items: new OA\Items(type: 'string'),
87+
default: [
88+
'id',
89+
'email',
90+
'confirmed',
91+
'blacklisted',
92+
'bounceCount',
93+
'createdAt',
94+
'updatedAt',
95+
'uniqueId',
96+
'htmlEmail',
97+
'disabled',
98+
'extraData',
99+
],
100+
),
101+
],
102+
type: 'object'
103+
)]
104+
56105
class SwaggerSchemasRequest
57106
{
58107
}

src/Subscription/Request/SubscribersExportRequest.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,15 @@ class SubscribersExportRequest implements RequestInterface
5252

5353
private function resolveDates(): array
5454
{
55-
$dateFrom = new DateTimeImmutable($this->dateFrom);
56-
$dateTo = new DateTimeImmutable($this->dateTo);
55+
$dateFrom = $this->dateFrom ? new DateTimeImmutable($this->dateFrom) : null;
56+
$dateTo = $this->dateTo ? new DateTimeImmutable($this->dateTo) : null;
5757

5858
return match ($this->dateType) {
5959
'subscribed' => [$dateFrom, $dateTo, null, null, null, null],
6060
'signup' => [null, null, $dateFrom, $dateTo, null, null],
6161
'changed' => [null, null, null, null, $dateFrom, $dateTo],
6262
'any', 'changelog' => [null, null, null, null, null, null],
63+
default => [null, null, null, null, null, null],
6364
};
6465
}
6566

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpList\RestBundle\Tests\Integration\Subscription\Controller;
6+
7+
use PhpList\RestBundle\Subscription\Controller\SubscriberExportController;
8+
use PhpList\RestBundle\Tests\Integration\Common\AbstractTestController;
9+
use Symfony\Component\HttpFoundation\Response;
10+
11+
class SubscriberExportControllerTest extends AbstractTestController
12+
{
13+
public function testControllerIsAvailableViaContainer(): void
14+
{
15+
self::assertInstanceOf(
16+
SubscriberExportController::class,
17+
self::getContainer()->get(SubscriberExportController::class)
18+
);
19+
}
20+
21+
public function testExportSubscribersWithoutSessionKeyReturnsForbiddenStatus(): void
22+
{
23+
$this->jsonRequest('POST', '/api/v2/subscribers/export');
24+
25+
$this->assertHttpForbidden();
26+
}
27+
28+
public function testExportSubscribersWithInvalidRequestReturnsUnprocessableEntityStatus(): void
29+
{
30+
$this->authenticatedJsonRequest(
31+
'POST',
32+
'/api/v2/subscribers/export',
33+
[],
34+
[],
35+
[],
36+
json_encode(['dateType' => 'invalid_type'])
37+
);
38+
39+
$this->assertHttpUnprocessableEntity();
40+
}
41+
42+
public function testExportSubscribersWithValidRequest(): void
43+
{
44+
$this->authenticatedJsonRequest(
45+
'POST',
46+
'/api/v2/subscribers/export',
47+
[],
48+
[],
49+
[],
50+
json_encode([
51+
'dateType' => 'any',
52+
'columns' => ['email', 'confirmed', 'blacklisted']
53+
])
54+
);
55+
56+
$response = self::getClient()->getResponse();
57+
self::assertSame(Response::HTTP_OK, $response->getStatusCode());
58+
self::assertStringContainsString('text/csv', $response->headers->get('Content-Type'));
59+
self::assertStringContainsString(
60+
'attachment; filename=subscribers_export_',
61+
$response->headers->get('Content-Disposition')
62+
);
63+
}
64+
65+
public function testExportSubscribersWithoutListIdFilter(): void
66+
{
67+
$this->authenticatedJsonRequest(
68+
'POST',
69+
'/api/v2/subscribers/export',
70+
[],
71+
[],
72+
[],
73+
json_encode([
74+
'dateType' => 'any',
75+
'columns' => ['email', 'confirmed', 'blacklisted']
76+
])
77+
);
78+
79+
$response = self::getClient()->getResponse();
80+
self::assertSame(Response::HTTP_OK, $response->getStatusCode());
81+
self::assertStringContainsString('text/csv', $response->headers->get('Content-Type'));
82+
}
83+
84+
public function testExportSubscribersWithSpecificColumns(): void
85+
{
86+
$this->authenticatedJsonRequest(
87+
'POST',
88+
'/api/v2/subscribers/export',
89+
[],
90+
[],
91+
[],
92+
json_encode([
93+
'dateType' => 'any',
94+
'columns' => ['email', 'confirmed']
95+
])
96+
);
97+
98+
$response = self::getClient()->getResponse();
99+
self::assertSame(Response::HTTP_OK, $response->getStatusCode());
100+
self::assertStringContainsString('text/csv', $response->headers->get('Content-Type'));
101+
}
102+
103+
public function testGetMethodIsNotAllowed(): void
104+
{
105+
$this->authenticatedJsonRequest('GET', '/api/v2/subscribers/export');
106+
107+
$this->assertHttpMethodNotAllowed();
108+
}
109+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpList\RestBundle\Tests\Unit\Subscription\Serializer;
6+
7+
use PhpList\RestBundle\Subscription\Request\SubscribersExportRequest;
8+
use PhpList\RestBundle\Subscription\Serializer\SubscribersExportRequestNormalizer;
9+
use PHPUnit\Framework\TestCase;
10+
use stdClass;
11+
12+
class SubscribersExportRequestNormalizerTest extends TestCase
13+
{
14+
public function testSupportsNormalization(): void
15+
{
16+
$normalizer = new SubscribersExportRequestNormalizer();
17+
$request = $this->createMock(SubscribersExportRequest::class);
18+
19+
$this->assertTrue($normalizer->supportsNormalization($request));
20+
$this->assertFalse($normalizer->supportsNormalization(new stdClass()));
21+
}
22+
23+
public function testNormalize(): void
24+
{
25+
$request = new SubscribersExportRequest();
26+
$request->dateType = 'signup';
27+
$request->listId = 123;
28+
$request->dateFrom = '2023-01-01';
29+
$request->dateTo = '2023-12-31';
30+
$request->columns = ['id', 'email', 'confirmed'];
31+
32+
$normalizer = new SubscribersExportRequestNormalizer();
33+
34+
$expected = [
35+
'date_type' => 'signup',
36+
'list_id' => 123,
37+
'date_from' => '2023-01-01',
38+
'date_to' => '2023-12-31',
39+
'columns' => ['id', 'email', 'confirmed'],
40+
];
41+
42+
$this->assertSame($expected, $normalizer->normalize($request));
43+
}
44+
45+
public function testNormalizeWithDefaultValues(): void
46+
{
47+
$request = new SubscribersExportRequest();
48+
49+
$normalizer = new SubscribersExportRequestNormalizer();
50+
51+
$expected = [
52+
'date_type' => 'any',
53+
'list_id' => null,
54+
'date_from' => null,
55+
'date_to' => null,
56+
'columns' => [
57+
'id',
58+
'email',
59+
'confirmed',
60+
'blacklisted',
61+
'bounceCount',
62+
'createdAt',
63+
'updatedAt',
64+
'uniqueId',
65+
'htmlEmail',
66+
'disabled',
67+
'extraData'
68+
],
69+
];
70+
71+
$this->assertSame($expected, $normalizer->normalize($request));
72+
}
73+
74+
public function testNormalizeWithInvalidObject(): void
75+
{
76+
$normalizer = new SubscribersExportRequestNormalizer();
77+
$this->assertSame([], $normalizer->normalize(new stdClass()));
78+
}
79+
}

0 commit comments

Comments
 (0)