Skip to content

Commit 030325b

Browse files
committed
[FEATURE] POST subscriptions route
1 parent c31d6f9 commit 030325b

File tree

4 files changed

+424
-0
lines changed

4 files changed

+424
-0
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ This project adheres to [Semantic Versioning](https://semver.org/).
1010
- Run the system test on Travis (#113)
1111
- Add security headers to the default response (#110)
1212
- Whitelist BadRequestHttpException so that messages are not sanitized (#108)
13+
- REST API endpoint for adding a subscriber to a list
1314

1415
### Changed
1516

docs/Api/RestApi.apib

+70
Original file line numberDiff line numberDiff line change
@@ -392,3 +392,73 @@ object containing the following key-value pairs:
392392
"code": 422,
393393
"message": "Some fields invalid: email, confirmed, html_email"
394394
}
395+
396+
# Subscriptions
397+
398+
Resources related to subscriptions.
399+
400+
All requests in this group need to be authenticated with a valid session key
401+
provided as basic auth password. (The basic auth user name can be any string.)
402+
403+
## Subscriptions [/subscriptions]
404+
405+
### Create a new subscription [POST]
406+
407+
Given a valid authentication, this will generate a subscription, which means add a member to a list.
408+
It takes a JSON object containing the following key-value pairs:
409+
410+
+ `subscriber_id` (integer): ID of the subscriber (required)
411+
+ `subscriber_list_id` (integer): ID of the list (required)
412+
413+
+ Response 201 (application/json)
414+
415+
+ Body
416+
417+
{
418+
"creation_date": "2020-01-09T18:44:27+00:00",
419+
}
420+
421+
+ Response 403 (application/json)
422+
423+
+ Body
424+
425+
{
426+
"code": 403,
427+
"message": "No valid session key was provided as basic auth password."
428+
}
429+
430+
+ Response 409 (application/json)
431+
432+
+ Body
433+
434+
{
435+
"code": 409,
436+
"message": "This resource already exists."
437+
}
438+
439+
+ Response 422 (application/json)
440+
441+
+ Body
442+
443+
{
444+
"code": 422,
445+
"message": "Some fields invalid: subscriber_id, subscriber_list_id"
446+
}
447+
448+
+ Response 422 (application/json)
449+
450+
+ Body
451+
452+
{
453+
"code": 422,
454+
"message": "subscriber_id not found: 42"
455+
}
456+
457+
+ Response 422 (application/json)
458+
459+
+ Body
460+
461+
{
462+
"code": 422,
463+
"message": "subscriber_list_id not found: 42"
464+
}
+130
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace PhpList\RestBundle\Controller;
5+
6+
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
7+
use FOS\RestBundle\Controller\FOSRestController;
8+
use FOS\RestBundle\Routing\ClassResourceInterface;
9+
use FOS\RestBundle\View\View;
10+
use PhpList\Core\Domain\Model\Subscription\Subscription;
11+
use PhpList\Core\Domain\Repository\Messaging\SubscriberListRepository;
12+
use PhpList\Core\Domain\Repository\Subscription\SubscriberRepository;
13+
use PhpList\Core\Domain\Repository\Subscription\SubscriptionRepository;
14+
use PhpList\Core\Security\Authentication;
15+
use PhpList\RestBundle\Controller\Traits\AuthenticationTrait;
16+
use Symfony\Component\HttpFoundation\Request;
17+
use Symfony\Component\HttpFoundation\Response;
18+
use Symfony\Component\HttpKernel\Exception\ConflictHttpException;
19+
use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;
20+
21+
/**
22+
* This controller provides REST API access to subscriptions.
23+
*
24+
* @author Matthieu Robin <[email protected]>
25+
*/
26+
class SubscriptionController extends FOSRestController implements ClassResourceInterface
27+
{
28+
use AuthenticationTrait;
29+
30+
/**
31+
* @var SubscriberRepository
32+
*/
33+
private $subscriberRepository = null;
34+
35+
/**
36+
* @var SubscriberListRepository
37+
*/
38+
private $subscriberListRepository;
39+
40+
/**
41+
* @var SubscriptionRepository
42+
*/
43+
private $subscriptionRepository;
44+
45+
/**
46+
* @param Authentication $authentication
47+
* @param SubscriberRepository|null $subscriberRepository
48+
* @param SubscriberListRepository $subscriberListRepository
49+
* @param SubscriptionRepository $subscriptionRepository
50+
*/
51+
public function __construct(
52+
Authentication $authentication,
53+
SubscriberRepository $subscriberRepository,
54+
SubscriberListRepository $subscriberListRepository,
55+
SubscriptionRepository $subscriptionRepository
56+
) {
57+
$this->authentication = $authentication;
58+
$this->subscriberRepository = $subscriberRepository;
59+
$this->subscriberListRepository = $subscriberListRepository;
60+
$this->subscriptionRepository = $subscriptionRepository;
61+
}
62+
63+
/**
64+
* Creates a new subscription.
65+
*
66+
* @param Request $request
67+
*
68+
* @return View
69+
*
70+
* @throws UnprocessableEntityHttpException
71+
* @throws ConflictHttpException
72+
*/
73+
public function postAction(Request $request): View
74+
{
75+
$this->requireAuthentication($request);
76+
77+
$this->validateSubscription($request);
78+
79+
$subscriber = $this->subscriberRepository->findOneById($request->get('subscriber_id'));
80+
if ($subscriber === null) {
81+
throw new UnprocessableEntityHttpException(
82+
'subscriber_id not found: '.$request->get('subscriber_id'),
83+
null,
84+
1598917596
85+
);
86+
}
87+
88+
$subscriberList = $this->subscriberListRepository->findOneById($request->get('subscriber_list_id'));
89+
if ($subscriberList === null) {
90+
throw new UnprocessableEntityHttpException(
91+
'subscriber_list_id not found: '.$request->get('subscriber_list_id'),
92+
null,
93+
1598917574
94+
);
95+
}
96+
97+
$subscription = new Subscription();
98+
$subscription->setSubscriber($subscriber);
99+
$subscription->setSubscriberList($subscriberList);
100+
101+
try {
102+
$this->subscriptionRepository->save($subscription);
103+
} catch (UniqueConstraintViolationException $e) {
104+
throw new ConflictHttpException('This resource already exists.', null, 1598918448);
105+
}
106+
107+
return View::create()->setStatusCode(Response::HTTP_CREATED)->setData($subscription);
108+
}
109+
110+
private function validateSubscription(Request $request)
111+
{
112+
/** @var string[] $invalidFields */
113+
$invalidFields = [];
114+
if (filter_var($request->get('subscriber_id'), FILTER_VALIDATE_INT) === false) {
115+
$invalidFields[] = 'subscriber_id';
116+
}
117+
118+
if (filter_var($request->get('subscriber_list_id'), FILTER_VALIDATE_INT) === false) {
119+
$invalidFields[] = 'subscriber_list_id';
120+
}
121+
122+
if (!empty($invalidFields)) {
123+
throw new UnprocessableEntityHttpException(
124+
'Some fields invalid:' . implode(', ', $invalidFields),
125+
null,
126+
1598914359
127+
);
128+
}
129+
}
130+
}

0 commit comments

Comments
 (0)