Skip to content

Commit

Permalink
[FEATURE] POST subscriptions route
Browse files Browse the repository at this point in the history
  • Loading branch information
meetic-mrobin committed Sep 1, 2020
1 parent 7590bcd commit 666e320
Show file tree
Hide file tree
Showing 4 changed files with 424 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ This project adheres to [Semantic Versioning](https://semver.org/).
- Run the system test on Travis (#113)
- Add security headers to the default response (#110)
- Whitelist BadRequestHttpException so that messages are not sanitized (#108)
- REST API endpoint for adding a subscriber to a list

### Changed

Expand Down
70 changes: 70 additions & 0 deletions docs/Api/RestApi.apib
Original file line number Diff line number Diff line change
Expand Up @@ -392,3 +392,73 @@ object containing the following key-value pairs:
"code": 422,
"message": "Some fields invalid: email, confirmed, html_email"
}

# Subscriptions

Resources related to subscriptions.

All requests in this group need to be authenticated with a valid session key
provided as basic auth password. (The basic auth user name can be any string.)

## Subscriptions [/subscriptions]

### Create a new subscription [POST]

Given a valid authentication, this will generate a subscription, which means add a member to a list.
It takes a JSON object containing the following key-value pairs:

+ `subscriber_id` (integer): ID of the subscriber (required)
+ `subscriber_list_id` (integer): ID of the list (required)

+ Response 201 (application/json)

+ Body

{
"creation_date": "2020-01-09T18:44:27+00:00",
}

+ Response 403 (application/json)

+ Body

{
"code": 403,
"message": "No valid session key was provided as basic auth password."
}

+ Response 409 (application/json)

+ Body

{
"code": 409,
"message": "This resource already exists."
}

+ Response 422 (application/json)

+ Body

{
"code": 422,
"message": "Some fields invalid: subscriber_id, subscriber_list_id"
}

+ Response 422 (application/json)

+ Body

{
"code": 422,
"message": "subscriber_id not found: 42"
}

+ Response 422 (application/json)

+ Body

{
"code": 422,
"message": "subscriber_list_id not found: 42"
}
130 changes: 130 additions & 0 deletions src/Controller/SubscriptionController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
<?php
declare(strict_types=1);

namespace PhpList\RestBundle\Controller;

use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
use FOS\RestBundle\Controller\FOSRestController;
use FOS\RestBundle\Routing\ClassResourceInterface;
use FOS\RestBundle\View\View;
use PhpList\Core\Domain\Model\Subscription\Subscription;
use PhpList\Core\Domain\Repository\Messaging\SubscriberListRepository;
use PhpList\Core\Domain\Repository\Subscription\SubscriberRepository;
use PhpList\Core\Domain\Repository\Subscription\SubscriptionRepository;
use PhpList\Core\Security\Authentication;
use PhpList\RestBundle\Controller\Traits\AuthenticationTrait;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\ConflictHttpException;
use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;

/**
* This controller provides REST API access to subscriptions.
*
* @author Matthieu Robin <[email protected]>
*/
class SubscriptionController extends FOSRestController implements ClassResourceInterface
{
use AuthenticationTrait;

/**
* @var SubscriberRepository
*/
private $subscriberRepository = null;

/**
* @var SubscriberListRepository
*/
private $subscriberListRepository;

/**
* @var SubscriptionRepository
*/
private $subscriptionRepository;

/**
* @param Authentication $authentication
* @param SubscriberRepository|null $subscriberRepository
* @param SubscriberListRepository $subscriberListRepository
* @param SubscriptionRepository $subscriptionRepository
*/
public function __construct(
Authentication $authentication,
SubscriberRepository $subscriberRepository,
SubscriberListRepository $subscriberListRepository,
SubscriptionRepository $subscriptionRepository
) {
$this->authentication = $authentication;
$this->subscriberRepository = $subscriberRepository;
$this->subscriberListRepository = $subscriberListRepository;
$this->subscriptionRepository = $subscriptionRepository;
}

/**
* Creates a new subscription.
*
* @param Request $request
*
* @return View
*
* @throws UnprocessableEntityHttpException
* @throws ConflictHttpException
*/
public function postAction(Request $request): View
{
$this->requireAuthentication($request);

$this->validateSubscription($request);

$subscriber = $this->subscriberRepository->findOneById($request->get('subscriber_id'));
if ($subscriber === null) {
throw new UnprocessableEntityHttpException(
'subscriber_id not found: '.$request->get('subscriber_id'),
null,
1598917596
);
}

$subscriberList = $this->subscriberListRepository->findOneById($request->get('subscriber_list_id'));
if ($subscriberList === null) {
throw new UnprocessableEntityHttpException(
'subscriber_list_id not found: '.$request->get('subscriber_list_id'),
null,
1598917574
);
}

$subscription = new Subscription();
$subscription->setSubscriber($subscriber);
$subscription->setSubscriberList($subscriberList);

try {
$this->subscriptionRepository->save($subscription);
} catch (UniqueConstraintViolationException $e) {
throw new ConflictHttpException('This resource already exists.', null, 1598918448);
}

return View::create()->setStatusCode(Response::HTTP_CREATED)->setData($subscription);
}

private function validateSubscription(Request $request)
{
/** @var string[] $invalidFields */
$invalidFields = [];
if (filter_var($request->get('subscriber_id'), FILTER_VALIDATE_INT) === false) {
$invalidFields[] = 'subscriber_id';
}

if (filter_var($request->get('subscriber_list_id'), FILTER_VALIDATE_INT) === false) {
$invalidFields[] = 'subscriber_list_id';
}

if (!empty($invalidFields)) {
throw new UnprocessableEntityHttpException(
'Some fields invalid:' . implode(', ', $invalidFields),
null,
1598914359
);
}
}
}
Loading

0 comments on commit 666e320

Please sign in to comment.