Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ headers {
body:json {
{
"emails": [
"eliot@rezo-zero.com"
"john.doe@contact.com"
]
}
}
29 changes: 29 additions & 0 deletions bruno/subscribeme/Brevo/Get a Contact.bru
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
meta {
name: Get a Contact
type: http
seq: 6
}

get {
url: {{brevo_base_url}}/v3/contacts/:identifier?startDate=&endDate=
body: none
auth: none
}

params:query {
~startDate:
~endDate:
}

params:path {
identifier:
}

headers {
api-key: {{brevo_api_key}}
}

settings {
encodeUrl: true
timeout: 0
}
24 changes: 24 additions & 0 deletions bruno/subscribeme/Brevo/Get a list's details.bru
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
meta {
name: Get a list's details
type: http
seq: 7
}

get {
url: {{brevo_base_url}}/v3/contacts/lists/:listId
body: none
auth: none
}

params:path {
listId: 4
}

headers {
api-key: {{brevo_api_key}}
}

settings {
encodeUrl: true
timeout: 0
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ auth:basic {
body:json {
{
"contacts" : {
"email@rezo-zero.com": {
"email@test.com": {
"firstName": "firstName",
"lastName": "lastName"
}
Expand Down
7 changes: 6 additions & 1 deletion src/SubscribeMe/Exception/ApiResponseException.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

final class ApiResponseException extends \RuntimeException
{
public function __construct(private array $responseBody, Throwable $previous = null)
public function __construct(private array $responseBody, ?Throwable $previous = null, private ?int $statusCode = null)
{
parent::__construct('Api response error', 0, $previous);
}
Expand All @@ -17,4 +17,9 @@ public function getResponseBody(): array
{
return $this->responseBody;
}

public function getStatusCode(): ?int
{
return $this->statusCode;
}
}
28 changes: 21 additions & 7 deletions src/SubscribeMe/Subscriber/BrevoSubscriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@

namespace SubscribeMe\Subscriber;

use JsonException;
use Psr\Http\Client\ClientExceptionInterface;
use SubscribeMe\Exception\ApiResponseException;
use SubscribeMe\Exception\CannotSendTransactionalEmailException;
use SubscribeMe\Exception\CannotSubscribeException;
use SubscribeMe\Exception\ApiCredentialsException;
use SubscribeMe\Exception\UnsupportedUnsubscribePlatformException;
use SubscribeMe\GDPR\UserConsent;
use SubscribeMe\ValueObject\EmailAddress;

Expand Down Expand Up @@ -84,7 +82,7 @@ protected function getAttributes(array $options, array $userConsents = []): arra
}

/**
* @throws JsonException
* @throws \JsonException|ApiResponseException
*/
protected function doSubscribe(string $uri, array $body): bool|int
{
Expand Down Expand Up @@ -122,12 +120,20 @@ protected function doSubscribe(string $uri, array $body): bool|int
$body['message'] == 'Contact already exist') {
return true;
}

return false;
}

/*
* Any other status code (401, 403, 429, 5xx…) is an unexpected error: do not fail
* silently, surface the status code and response body so the caller can diagnose it.
*/
/** @var array $body */
$body = json_decode($res->getBody()->getContents(), true) ?? [];
throw new ApiResponseException($body, null, $res->getStatusCode());
} catch (ClientExceptionInterface $exception) {
throw new CannotSubscribeException($exception->getMessage(), $exception);
}

return false;
}

/**
Expand Down Expand Up @@ -241,11 +247,19 @@ public function unsubscribe(string $email): bool
if (isset($body['success'])) {
return true;
}

return false;
}

/*
* Any other status code (401, 403, 429, 5xx…) is an unexpected error: do not fail
* silently, surface the status code and response body so the caller can diagnose it.
*/
/** @var array $body */
$body = json_decode($res->getBody()->getContents(), true) ?? [];
throw new ApiResponseException($body, null, $res->getStatusCode());
} catch (ClientExceptionInterface $exception) {
throw new CannotSubscribeException($exception->getMessage(), $exception);
}

return false;
}
}
2 changes: 1 addition & 1 deletion src/SubscribeMe/Subscriber/ResponseValidationTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ protected function validateResponse(ResponseInterface $response): string
}
/** @var array $result */
$result = json_decode($response->getBody()->getContents(), true);
throw new ApiResponseException($result);
throw new ApiResponseException($result, null, $response->getStatusCode());
}
}
5 changes: 3 additions & 2 deletions src/SubscribeMe/Subscriber/SubscriberInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace SubscribeMe\Subscriber;

use JsonException;
use SubscribeMe\Exception\ApiResponseException;
use SubscribeMe\Exception\UnsupportedTransactionalEmailPlatformException;
use SubscribeMe\Exception\UnsupportedUnsubscribePlatformException;
use SubscribeMe\GDPR\UserConsent;
Expand All @@ -25,14 +26,14 @@ public function setContactListId(?string $contactListId): SubscriberInterface;
* @param array $options
* @param UserConsent[] $userConsents
* @return bool|int Contact ID if succeeded or false
* @throws JsonException
* @throws JsonException|ApiResponseException
*/
public function subscribe(string $email, array $options, array $userConsents = []): bool|int;

/**
* @param string $email
* @return bool true on succeeded or false
* @throws JsonException|UnsupportedUnsubscribePlatformException
* @throws JsonException|UnsupportedUnsubscribePlatformException|ApiResponseException
*/
public function unsubscribe(string $email): bool;

Expand Down
51 changes: 51 additions & 0 deletions tests/BrevoMailerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Nyholm\Psr7\Response;
use PHPUnit\Framework\TestCase;
use SubscribeMe\Exception\ApiCredentialsException;
use SubscribeMe\Exception\ApiResponseException;
use SubscribeMe\Exception\CannotSendTransactionalEmailException;
use SubscribeMe\Subscriber\BrevoSubscriber;
use SubscribeMe\ValueObject\EmailAddress;
Expand Down Expand Up @@ -160,6 +161,56 @@ public function testSubscribeWithoutId(): void
$this->assertEquals('api.brevo.com', $requests[0]->getUri()->getHost());
}

/**
* @throws JsonException
*/
public function testSubscribeThrowsOnUnauthorized(): void
{
$client = new Client();
$factory = new Psr17Factory();

$client->setDefaultResponse(
new Response(401, [], json_encode(['message' => 'IP address not authorized'], JSON_THROW_ON_ERROR))
);

$brevoSubscriber = new BrevoSubscriber($client, $factory, $factory);
$brevoSubscriber->setContactListId('3,5');
$brevoSubscriber->setApiKey('928f601b-5476-4480-8eb0-c8d979f3b68f');

try {
$brevoSubscriber->subscribe('elly@example.com', []);
$this->fail('Expected ApiResponseException was not thrown.');
} catch (ApiResponseException $exception) {
$this->assertSame(401, $exception->getStatusCode());
$this->assertSame('IP address not authorized', $exception->getResponseBody()['message']);
}
}

/**
* @throws JsonException
*/
public function testUnsubscribeThrowsOnUnauthorized(): void
{
$client = new Client();
$factory = new Psr17Factory();

$client->setDefaultResponse(
new Response(401, [], json_encode(['message' => 'IP address not authorized'], JSON_THROW_ON_ERROR))
);

$brevoSubscriber = new BrevoSubscriber($client, $factory, $factory);
$brevoSubscriber->setContactListId('3');
$brevoSubscriber->setApiKey('928f601b-5476-4480-8eb0-c8d979f3b68f');

try {
$brevoSubscriber->unsubscribe('elly@example.com');
$this->fail('Expected ApiResponseException was not thrown.');
} catch (ApiResponseException $exception) {
$this->assertSame(401, $exception->getStatusCode());
$this->assertSame('IP address not authorized', $exception->getResponseBody()['message']);
}
}

/**
* @throws JsonException
*/
Expand Down
Loading