Skip to content

Commit 6ad001f

Browse files
committed
Add: Default templates endpoints
1 parent 93cc52e commit 6ad001f

7 files changed

Lines changed: 191 additions & 4 deletions

File tree

src/Messaging/Controller/TemplateController.php

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,98 @@ className: Template::class,
116116
);
117117
}
118118

119+
#[Route('/defaults', name: 'get_defaults', methods: ['GET'])]
120+
#[OA\Get(
121+
path: '/api/v2/templates/defaults',
122+
description: '🚧 **Status: Beta** – This method is under development. Avoid using in production. ' .
123+
'Returns a JSON list of all available default templates.',
124+
summary: 'Gets a list of all default templates.',
125+
tags: ['templates'],
126+
parameters: [
127+
new OA\Parameter(
128+
name: 'php-auth-pw',
129+
description: 'Session key obtained from login',
130+
in: 'header',
131+
required: true,
132+
schema: new OA\Schema(type: 'string')
133+
),
134+
],
135+
responses: [
136+
new OA\Response(
137+
response: 200,
138+
description: 'Success',
139+
content: new OA\JsonContent(
140+
type: 'array',
141+
items: new OA\Items(
142+
properties: [
143+
new OA\Property(property: 'key', type: 'string', example: 'system'),
144+
new OA\Property(property: 'name', type: 'string', example: 'System'),
145+
new OA\Property(property: 'description', type: 'string', example: 'Default system email'),
146+
new OA\Property(property: 'file', type: 'string', example: 'system.html'),
147+
],
148+
type: 'object'
149+
) )
150+
),
151+
new OA\Response(
152+
response: 403,
153+
description: 'Failure',
154+
content: new OA\JsonContent(ref: '#/components/schemas/UnauthorizedResponse')
155+
)
156+
]
157+
)]
158+
public function listDefaults(Request $request): JsonResponse
159+
{
160+
$this->requireAuthentication($request);
161+
162+
return $this->json($this->templateManager->listDefaults(), Response::HTTP_OK);
163+
}
164+
165+
#[Route('/defaults/{key}', name: 'create_default', methods: ['POST'])]
166+
#[OA\Post(
167+
path: '/api/v2/templates/defaults/{key}',
168+
description: '🚧 **Status: Beta** – This method is under development. Avoid using in production. ' .
169+
'Creates a new template from a default template key.',
170+
summary: 'Creates a template from a default template.',
171+
tags: ['templates'],
172+
parameters: [
173+
new OA\Parameter(
174+
name: 'php-auth-pw',
175+
description: 'Session key obtained from login',
176+
in: 'header',
177+
required: true,
178+
schema: new OA\Schema(type: 'string')
179+
),
180+
new OA\Parameter(
181+
name: 'key',
182+
description: 'Default template key',
183+
in: 'path',
184+
required: true,
185+
schema: new OA\Schema(type: 'string', enum: ['system', 'responsive'])
186+
),
187+
],
188+
responses: [
189+
new OA\Response(
190+
response: 201,
191+
description: 'Success',
192+
content: new OA\JsonContent(ref: '#/components/schemas/Template')
193+
),
194+
new OA\Response(
195+
response: 403,
196+
description: 'Failure',
197+
content: new OA\JsonContent(ref: '#/components/schemas/UnauthorizedResponse')
198+
)
199+
]
200+
)]
201+
public function createDefaultTemplate(Request $request, string $key): JsonResponse
202+
{
203+
$this->requireAuthentication($request);
204+
205+
$template = $this->templateManager->createDefaultTemplate($key);
206+
$this->entityManager->flush();
207+
208+
return $this->json($this->normalizer->normalize($template), Response::HTTP_CREATED);
209+
}
210+
119211
#[Route('/{templateId}', name: 'get_one', requirements: ['templateId' => '\d+'], methods: ['GET'])]
120212
#[OA\Get(
121213
path: '/api/v2/templates/{templateId}',

src/Messaging/Request/CreateTemplateRequest.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
nullable: true
2525
),
2626
new OA\Property(property: 'text', type: 'string', example: '[CONTENT]'),
27+
new OA\Property(property: 'list_order', type: 'integer', example: 10, nullable: true),
2728
new OA\Property(
2829
property: 'file',
2930
description: 'Optional file upload for HTML content',
@@ -64,6 +65,8 @@ class CreateTemplateRequest implements RequestInterface
6465
#[ContainsPlaceholder]
6566
public ?string $text = null;
6667

68+
public ?int $listOrder = null;
69+
6770
public ?UploadedFile $file = null;
6871
public bool $checkLinks = false;
6972
public bool $checkImages = false;
@@ -79,6 +82,7 @@ public function getDto(): CreateTemplateDto
7982
shouldCheckLinks: $this->checkLinks,
8083
shouldCheckImages: $this->checkImages,
8184
shouldCheckExternalImages: $this->checkExternalImages,
85+
listOrder: $this->listOrder ?? 0,
8286
);
8387
}
8488
}

src/Messaging/Request/UpdateTemplateRequest.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
nullable: true
2626
),
2727
new OA\Property(property: 'text', type: 'string', example: '[CONTENT]'),
28+
new OA\Property(property: 'list_order', type: 'integer', example: 10, nullable: true),
2829
new OA\Property(
2930
property: 'file',
3031
description: 'Optional file upload for HTML content',
@@ -67,6 +68,8 @@ class UpdateTemplateRequest implements RequestInterface
6768
#[ContainsPlaceholder]
6869
public ?string $text = null;
6970

71+
public ?int $listOrder = null;
72+
7073
public ?UploadedFile $file = null;
7174
public bool $checkLinks = false;
7275
public bool $checkImages = false;
@@ -82,6 +85,7 @@ public function getDto(): UpdateTemplateDto
8285
shouldCheckLinks: $this->checkLinks,
8386
shouldCheckImages: $this->checkImages,
8487
shouldCheckExternalImages: $this->checkExternalImages,
88+
listOrder: $this->listOrder ?? 0,
8589
);
8690
}
8791
}

src/Messaging/Serializer/TemplateNormalizer.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
new OA\Property(property: 'title', type: 'string', example: 'Newsletter'),
1717
new OA\Property(property: 'content', type: 'string', example: 'Hello World!', nullable: true),
1818
new OA\Property(property: 'text', type: 'string', nullable: true),
19-
new OA\Property(property: 'order', type: 'integer', nullable: true),
19+
new OA\Property(property: 'list_order', type: 'integer', nullable: true),
2020
new OA\Property(
2121
property: 'images',
2222
type: 'array',
@@ -47,7 +47,7 @@ public function normalize($object, string $format = null, array $context = []):
4747
'title' => $object->getTitle(),
4848
'content' => $object->getContent(),
4949
'text' => $object->getText(),
50-
'order' => $object->getListOrder(),
50+
'list_order' => $object->getListOrder(),
5151
'images' => $object->getImages()->toArray() ? array_map(function (TemplateImage $image) {
5252
return $this->templateImageNormalizer->normalize($image);
5353
}, $object->getImages()->toArray()) : null

tests/Integration/Messaging/Controller/TemplateControllerTest.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,29 @@ public function testGetTemplatesReturnsTemplateData(): void
5757
self::assertArrayHasKey('title', $response['items'][0]);
5858
}
5959

60+
public function testListDefaultTemplatesWithValidSessionKeyReturnsOkay(): void
61+
{
62+
$this->authenticatedJsonRequest('GET', '/api/v2/templates/defaults');
63+
$this->assertHttpOkay();
64+
}
65+
66+
public function testCreateTemplateFromDefaultWithValidSessionKeyReturnsCreated(): void
67+
{
68+
$this->authenticatedJsonRequest('GET', '/api/v2/templates/defaults');
69+
$defaults = $this->getDecodedJsonResponseContent();
70+
71+
self::assertIsArray($defaults);
72+
self::assertNotEmpty($defaults);
73+
self::assertArrayHasKey('key', $defaults[0]);
74+
75+
$this->authenticatedJsonRequest('POST', '/api/v2/templates/defaults/' . $defaults[0]['key']);
76+
$this->assertHttpCreated();
77+
78+
$response = $this->getDecodedJsonResponseContent();
79+
self::assertArrayHasKey('id', $response);
80+
self::assertArrayHasKey('title', $response);
81+
}
82+
6083
public function testGetTemplateWithoutSessionKeyReturnsForbidden(): void
6184
{
6285
$this->loadFixtures([TemplateFixture::class]);
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpList\RestBundle\Tests\Unit\Messaging\Request;
6+
7+
use PhpList\Core\Domain\Messaging\Model\Dto\UpdateTemplateDto;
8+
use PhpList\RestBundle\Messaging\Request\UpdateTemplateRequest;
9+
use PHPUnit\Framework\TestCase;
10+
use Symfony\Component\HttpFoundation\File\UploadedFile;
11+
12+
class UpdateTemplateRequestTest extends TestCase
13+
{
14+
private UpdateTemplateRequest $request;
15+
16+
protected function setUp(): void
17+
{
18+
$this->request = new UpdateTemplateRequest();
19+
}
20+
21+
public function testGetDtoReturnsCorrectDto(): void
22+
{
23+
$this->request->title = 'Updated Template';
24+
$this->request->content = 'Updated [CONTENT]';
25+
$this->request->text = 'Updated text';
26+
$this->request->listOrder = 7;
27+
$this->request->checkLinks = true;
28+
$this->request->checkImages = true;
29+
$this->request->checkExternalImages = true;
30+
31+
$dto = $this->request->getDto();
32+
33+
$this->assertInstanceOf(UpdateTemplateDto::class, $dto);
34+
$this->assertSame('Updated Template', $dto->title);
35+
$this->assertSame('Updated [CONTENT]', $dto->content);
36+
$this->assertSame('Updated text', $dto->text);
37+
$this->assertNull($dto->fileContent);
38+
$this->assertTrue($dto->shouldCheckLinks);
39+
$this->assertTrue($dto->shouldCheckImages);
40+
$this->assertTrue($dto->shouldCheckExternalImages);
41+
$this->assertSame(7, $this->request->listOrder);
42+
}
43+
44+
public function testGetDtoWithUploadedFile(): void
45+
{
46+
$tempFile = tempnam(sys_get_temp_dir(), 'test');
47+
file_put_contents($tempFile, 'Updated file content');
48+
49+
$uploadedFile = $this->createMock(UploadedFile::class);
50+
$uploadedFile->method('getPathname')->willReturn($tempFile);
51+
52+
$this->request->title = 'Updated Template';
53+
$this->request->content = 'Updated [CONTENT]';
54+
$this->request->file = $uploadedFile;
55+
56+
$dto = $this->request->getDto();
57+
58+
$this->assertInstanceOf(UpdateTemplateDto::class, $dto);
59+
$this->assertSame('Updated file content', $dto->fileContent);
60+
$this->assertNull($this->request->listOrder);
61+
62+
unlink($tempFile);
63+
}
64+
}

tests/Unit/Messaging/Serializer/TemplateNormalizerTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public function testNormalizeTemplateWithImages(): void
5858
'title' => 'Test Template',
5959
'content' => '<html>Content</html>',
6060
'text' => 'Plain text',
61-
'order' => 5,
61+
'list_order' => 5,
6262
'images' => [
6363
[
6464
'id' => 100,
@@ -87,7 +87,7 @@ public function testNormalizeTemplateWithoutImages(): void
8787
'title' => 'Empty Template',
8888
'content' => '<html>No Images</html>',
8989
'text' => 'No images text',
90-
'order' => 0,
90+
'list_order' => 0,
9191
'images' => null
9292
], $normalized);
9393
}

0 commit comments

Comments
 (0)