Skip to content

Commit 0cebc96

Browse files
TatevikGrtatevikg1
andauthored
Refactor: admin attributes routes (#163)
API Changes Reorganized administrator attribute endpoints under a clearer /administrators/{id}/attributes structure. Standardized path parameter names to adminId and removed several exposed numeric ID fields from request payloads. Bug Fixes Consistent 404 responses when campaigns or related resources are not found. Documentation OpenAPI docs updated with new paths and improved schema references for template and message endpoints. * Fix: template request * Fix: template request content type --------- Co-authored-by: Tatevik <tatevikg1@gmail.com>
1 parent 3f084aa commit 0cebc96

File tree

15 files changed

+114
-118
lines changed

15 files changed

+114
-118
lines changed

src/Common/Validator/RequestValidator.php

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,9 @@ public function validate(Request $request, string $dtoClass): RequestInterface
2929
}
3030
$routeParams = $request->attributes->get('_route_params') ?? [];
3131

32-
if (isset($routeParams['subscriberId'])) {
33-
$routeParams['subscriberId'] = (int) $routeParams['subscriberId'];
34-
}
35-
if (isset($routeParams['messageId'])) {
36-
$routeParams['messageId'] = (int) $routeParams['messageId'];
37-
}
3832
if (isset($routeParams['listId'])) {
3933
$routeParams['listId'] = (int) $routeParams['listId'];
4034
}
41-
if (isset($routeParams['administratorId'])) {
42-
$routeParams['administratorId'] = (int) $routeParams['administratorId'];
43-
}
4435

4536
$data = array_merge($routeParams, $body ?? []);
4637

src/Identity/Controller/AdminAttributeValueController.php

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
use Symfony\Component\HttpFoundation\Response;
2323
use Symfony\Component\Routing\Attribute\Route;
2424

25-
#[Route('/administrators/attribute-values', name: 'admin_attribute_value_')]
25+
#[Route('/administrators', name: 'admin_attribute_value_')]
2626
class AdminAttributeValueController extends BaseController
2727
{
2828
private AdminAttributeManager $attributeManager;
@@ -46,13 +46,13 @@ public function __construct(
4646
}
4747

4848
#[Route(
49-
path: '/{adminId}/{definitionId}',
49+
path: '/{adminId}/attributes/{definitionId}',
5050
name: 'create',
5151
requirements: ['adminId' => '\d+', 'definitionId' => '\d+'],
5252
methods: ['POST', 'PUT'],
5353
)]
5454
#[OA\Post(
55-
path: '/api/v2/administrators/attribute-values/{adminId}/{definitionId}',
55+
path: '/api/v2/administrators/{adminId}/attributes/{definitionId}',
5656
description: '🚧 **Status: Beta** – This method is under development. Avoid using in production. ' .
5757
'Returns created/updated admin attribute.',
5858
summary: 'Create/update an admin attribute.',
@@ -133,13 +133,13 @@ public function createOrUpdate(
133133
}
134134

135135
#[Route(
136-
path: '/{adminId}/{definitionId}',
136+
path: '/{adminId}/attributes/{definitionId}',
137137
name: 'delete',
138138
requirements: ['adminId' => '\d+', 'definitionId' => '\d+'],
139139
methods: ['DELETE'],
140140
)]
141141
#[OA\Delete(
142-
path: '/api/v2/administrators/attribute-values/{adminId}/{definitionId}',
142+
path: '/api/v2/administrators/{adminId}/attributes/{definitionId}',
143143
description: '🚧 **Status: Beta** – This method is under development. Avoid using in production. ' .
144144
'Deletes a single admin attribute.',
145145
summary: 'Deletes an attribute.',
@@ -203,9 +203,9 @@ public function delete(
203203
return $this->json(null, Response::HTTP_NO_CONTENT);
204204
}
205205

206-
#[Route('/{adminId}', name: 'get__list', requirements: ['adminId' => '\d+'], methods: ['GET'])]
206+
#[Route('/{adminId}/attributes', name: 'get_list', requirements: ['adminId' => '\d+'], methods: ['GET'])]
207207
#[OA\Get(
208-
path: '/api/v2/administrators/attribute-values/{adminId}',
208+
path: '/api/v2/administrators/{adminId}/attributes',
209209
description: '🚧 **Status: Beta** – This method is under development. Avoid using in production. ' .
210210
'Returns a JSON list of all admin attributes.',
211211
summary: 'Gets a list of all admin attributes.',
@@ -260,6 +260,11 @@ public function delete(
260260
response: 403,
261261
description: 'Failure',
262262
content: new OA\JsonContent(ref: '#/components/schemas/UnauthorizedResponse')
263+
),
264+
new OA\Response(
265+
response: 404,
266+
description: 'Failure',
267+
content: new OA\JsonContent(ref: '#/components/schemas/NotFoundErrorResponse')
263268
)
264269
]
265270
)]
@@ -276,18 +281,18 @@ public function getPaginated(
276281

277282
return $this->json(
278283
$this->paginatedDataProvider->getPaginatedList(
279-
$request,
280-
$this->normalizer,
281-
AdminAttributeValue::class,
282-
$filter
284+
request: $request,
285+
normalizer:$this->normalizer,
286+
className: AdminAttributeValue::class,
287+
filter: $filter
283288
),
284289
Response::HTTP_OK
285290
);
286291
}
287292

288-
#[Route('/{adminId}/{definitionId}', name: 'get_one', methods: ['GET'])]
293+
#[Route('/{adminId}/attributes/{definitionId}', name: 'get_one', methods: ['GET'])]
289294
#[OA\Get(
290-
path: '/api/v2/administrators/attribute-values/{adminId}/{definitionId}',
295+
path: '/api/v2/administrators/{adminId}/attributes/{definitionId}',
291296
description: '🚧 **Status: Beta** – This method is under development. Avoid using in production. ' .
292297
'Returns a single attribute.',
293298
summary: 'Gets admin attribute.',
@@ -355,8 +360,6 @@ public function getAttributeDefinition(
355360
adminId: $admin->getId(),
356361
attributeDefinitionId: $definition->getId()
357362
);
358-
$this->attributeManager->delete($attribute);
359-
$this->entityManager->flush();
360363

361364
return $this->json(
362365
$this->normalizer->normalize($attribute),

src/Identity/Controller/AdministratorController.php

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -157,16 +157,16 @@ public function createAdministrator(
157157
return $this->json($json, Response::HTTP_CREATED);
158158
}
159159

160-
#[Route('/{administratorId}', name: 'get_one', requirements: ['administratorId' => '\d+'], methods: ['GET'])]
160+
#[Route('/{adminId}', name: 'get_one', requirements: ['adminId' => '\d+'], methods: ['GET'])]
161161
#[OA\Get(
162-
path: '/api/v2/administrators/{administratorId}',
162+
path: '/api/v2/administrators/{adminId}',
163163
description: '🚧 **Status: Beta** – This method is under development. Avoid using in production. ' .
164164
'Get administrator by ID.',
165165
summary: 'Get Administrator',
166166
tags: ['administrators'],
167167
parameters: [
168168
new OA\Parameter(
169-
name: 'administratorId',
169+
name: 'adminId',
170170
description: 'Administrator ID',
171171
in: 'path',
172172
required: true,
@@ -194,7 +194,7 @@ public function createAdministrator(
194194
)]
195195
public function getAdministrator(
196196
Request $request,
197-
#[MapEntity(mapping: ['administratorId' => 'id'])] ?Administrator $administrator,
197+
#[MapEntity(mapping: ['adminId' => 'id'])] ?Administrator $administrator,
198198
): JsonResponse {
199199
$this->requireAuthentication($request);
200200

@@ -206,9 +206,9 @@ public function getAdministrator(
206206
return $this->json($json, Response::HTTP_OK);
207207
}
208208

209-
#[Route('/{administratorId}', name: 'update', requirements: ['administratorId' => '\d+'], methods: ['PUT'])]
209+
#[Route('/{adminId}', name: 'update', requirements: ['adminId' => '\d+'], methods: ['PUT'])]
210210
#[OA\Put(
211-
path: '/api/v2/administrators/{administratorId}',
211+
path: '/api/v2/administrators/{adminId}',
212212
description: '🚧 **Status: Beta** – This method is under development. Avoid using in production. ' .
213213
'Update an administrator.',
214214
summary: 'Update Administrator',
@@ -220,7 +220,7 @@ public function getAdministrator(
220220
tags: ['administrators'],
221221
parameters: [
222222
new OA\Parameter(
223-
name: 'administratorId',
223+
name: 'adminId',
224224
description: 'Administrator ID',
225225
in: 'path',
226226
required: true,
@@ -248,7 +248,7 @@ public function getAdministrator(
248248
)]
249249
public function updateAdministrator(
250250
Request $request,
251-
#[MapEntity(mapping: ['administratorId' => 'id'])] ?Administrator $administrator,
251+
#[MapEntity(mapping: ['adminId' => 'id'])] ?Administrator $administrator,
252252
): JsonResponse {
253253
$this->requireAuthentication($request);
254254

@@ -263,16 +263,16 @@ public function updateAdministrator(
263263
return $this->json($this->normalizer->normalize($administrator), Response::HTTP_OK);
264264
}
265265

266-
#[Route('/{administratorId}', name: 'delete', requirements: ['administratorId' => '\d+'], methods: ['DELETE'])]
266+
#[Route('/{adminId}', name: 'delete', requirements: ['adminId' => '\d+'], methods: ['DELETE'])]
267267
#[OA\Delete(
268-
path: '/api/v2/administrators/{administratorId}',
268+
path: '/api/v2/administrators/{adminId}',
269269
description: '🚧 **Status: Beta** – This method is under development. Avoid using in production. ' .
270270
'Delete an administrator.',
271271
summary: 'Delete Administrator',
272272
tags: ['administrators'],
273273
parameters: [
274274
new OA\Parameter(
275-
name: 'administratorId',
275+
name: 'adminId',
276276
description: 'Administrator ID',
277277
in: 'path',
278278
required: true,
@@ -299,7 +299,7 @@ public function updateAdministrator(
299299
)]
300300
public function deleteAdministrator(
301301
Request $request,
302-
#[MapEntity(mapping: ['administratorId' => 'id'])] ?Administrator $administrator
302+
#[MapEntity(mapping: ['adminId' => 'id'])] ?Administrator $administrator
303303
): JsonResponse {
304304
$this->requireAuthentication($request);
305305

src/Identity/Request/UpdateAdministratorRequest.php

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,6 @@
5858
)]
5959
class UpdateAdministratorRequest implements RequestInterface
6060
{
61-
public int $administratorId;
62-
6361
#[Assert\Length(min: 3, max: 255)]
6462
#[UniqueLoginName]
6563
public ?string $loginName = null;
@@ -89,7 +87,6 @@ class UpdateAdministratorRequest implements RequestInterface
8987
public function getDto(): UpdateAdministratorDto
9088
{
9189
return new UpdateAdministratorDto(
92-
administratorId: $this->administratorId,
9390
loginName: $this->loginName,
9491
password: $this->password,
9592
email: $this->email,

src/Messaging/Controller/CampaignController.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,13 +144,21 @@ public function getMessages(Request $request): JsonResponse
144144
response: 403,
145145
description: 'Failure',
146146
content: new OA\JsonContent(ref: '#/components/schemas/UnauthorizedResponse')
147+
),
148+
new OA\Response(
149+
response: 404,
150+
description: 'Failure',
151+
content: new OA\JsonContent(ref: '#/components/schemas/NotFoundErrorResponse')
147152
)
148153
]
149154
)]
150155
public function getMessage(
151156
Request $request,
152157
#[MapEntity(mapping: ['messageId' => 'id'])] ?Message $message = null
153158
): JsonResponse {
159+
if ($message === null) {
160+
throw $this->createNotFoundException('Campaign not found.');
161+
}
154162
$this->requireAuthentication($request);
155163

156164
return $this->json($this->campaignService->getMessage($message), Response::HTTP_OK);
@@ -271,6 +279,11 @@ public function createMessage(Request $request): JsonResponse
271279
description: 'Failure',
272280
content: new OA\JsonContent(ref: '#/components/schemas/UnauthorizedResponse')
273281
),
282+
new OA\Response(
283+
response: 404,
284+
description: 'Failure',
285+
content: new OA\JsonContent(ref: '#/components/schemas/NotFoundErrorResponse')
286+
),
274287
new OA\Response(
275288
response: 422,
276289
description: 'Failure',
@@ -282,6 +295,9 @@ public function updateMessage(
282295
Request $request,
283296
#[MapEntity(mapping: ['messageId' => 'id'])] ?Message $message = null,
284297
): JsonResponse {
298+
if ($message === null) {
299+
throw $this->createNotFoundException('Campaign not found.');
300+
}
285301
$authUser = $this->requireAuthentication($request);
286302

287303
/** @var UpdateMessageRequest $updateMessageRequest */

src/Messaging/Controller/TemplateController.php

Lines changed: 4 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,9 @@ public function getTemplates(Request $request): JsonResponse
105105

106106
return $this->json(
107107
$this->paginatedDataProvider->getPaginatedList(
108-
$request,
109-
$this->normalizer,
110-
Template::class,
108+
request: $request,
109+
normalizer: $this->normalizer,
110+
className: Template::class,
111111
),
112112
Response::HTTP_OK
113113
);
@@ -178,51 +178,7 @@ public function getTemplate(
178178
required: true,
179179
content: new OA\MediaType(
180180
mediaType: 'multipart/form-data',
181-
schema: new OA\Schema(
182-
required: ['title'],
183-
properties: [
184-
new OA\Property(
185-
property: 'title',
186-
type: 'string',
187-
example: 'Newsletter Template'
188-
),
189-
new OA\Property(
190-
property: 'content',
191-
type: 'string',
192-
example: '<html><body>[CONTENT]</body></html>'
193-
),
194-
new OA\Property(
195-
property: 'text',
196-
type: 'string',
197-
example: '[CONTENT]'
198-
),
199-
new OA\Property(
200-
property: 'file',
201-
description: 'Optional file upload for HTML content',
202-
type: 'string',
203-
format: 'binary'
204-
),
205-
new OA\Property(
206-
property: 'check_links',
207-
description: 'Check that all links have full URLs',
208-
type: 'boolean',
209-
example: true
210-
),
211-
new OA\Property(
212-
property: 'check_images',
213-
description: 'Check that all images have full URLs',
214-
type: 'boolean',
215-
example: false
216-
),
217-
new OA\Property(
218-
property: 'check_external_images',
219-
description: 'Check that all external images exist',
220-
type: 'boolean',
221-
example: true
222-
),
223-
],
224-
type: 'object'
225-
)
181+
schema: new OA\Schema(ref: '#/components/schemas/CreateTemplateRequest')
226182
)
227183
),
228184
tags: ['templates'],

src/Messaging/Request/CreateTemplateRequest.php

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,60 @@
44

55
namespace PhpList\RestBundle\Messaging\Request;
66

7+
use OpenApi\Attributes as OA;
78
use PhpList\Core\Domain\Messaging\Model\Dto\CreateTemplateDto;
89
use PhpList\RestBundle\Common\Request\RequestInterface;
910
use PhpList\RestBundle\Messaging\Validator\Constraint\ContainsPlaceholder;
1011
use Symfony\Component\HttpFoundation\File\UploadedFile;
1112
use Symfony\Component\Validator\Constraints as Assert;
1213

14+
#[OA\Schema(
15+
schema: 'CreateTemplateRequest',
16+
required: ['title'],
17+
properties: [
18+
new OA\Property(property: 'title', type: 'string', example: 'Newsletter Template'),
19+
new OA\Property(
20+
property: 'content',
21+
type: 'string',
22+
example: '<html><body>[CONTENT]</body></html>',
23+
nullable: true
24+
),
25+
new OA\Property(property: 'text', type: 'string', example: '[CONTENT]'),
26+
new OA\Property(
27+
property: 'file',
28+
description: 'Optional file upload for HTML content',
29+
type: 'string',
30+
format: 'binary'
31+
),
32+
new OA\Property(
33+
property: 'check_links',
34+
description: 'Check that all links have full URLs',
35+
type: 'boolean',
36+
example: true
37+
),
38+
new OA\Property(
39+
property: 'check_images',
40+
description: 'Check that all images have full URLs',
41+
type: 'boolean',
42+
example: false
43+
),
44+
new OA\Property(
45+
property: 'check_external_images',
46+
description: 'Check that all external images exist',
47+
type: 'boolean',
48+
example: true
49+
),
50+
],
51+
type: 'object'
52+
)]
1353
class CreateTemplateRequest implements RequestInterface
1454
{
1555
#[Assert\NotBlank(normalizer: 'trim')]
1656
#[Assert\NotNull]
1757
public string $title;
1858

19-
#[Assert\NotBlank]
2059
#[ContainsPlaceholder]
21-
public string $content;
60+
public ?string $content = null;
2261

2362
#[ContainsPlaceholder]
2463
public ?string $text = null;

0 commit comments

Comments
 (0)